docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Manage API Layers

    This page describes how to import, remove, enable, disable, and reorder OpenXR API layers in your Unity project.

    You can perform the following operations to manage an OpenXR layer for your project:

    • Import: Copies the layer library and manifest files into the XR/APILayers~ folder and adds the layer to the OpenXR settings.
    • Remove: Reverses the import operation, removing the files copied to the XR/APILayers~ folder.
    • Enable: Updates the OpenXR settings so that the API layer is included in a build and loaded at runtime.
    • Disable: Updates the OpenXR settings so that the API layer is NOT included in a build and NOT loaded at runtime.
    • Reorder: API layers are loaded in the order in which they appear in the APILayers.collection property. You can change the order of the members of this collection in case one layer must load before or after another layer.

    You can perform these operations using the APILayersFeature and APILayers classes.

    Tip

    You perform all API layer management in the Unity Editor. These operations modify your Unity project's OpenXR settings and project structure.

    If your application or OpenXR API layer has complex setup requirements, you can implement the ISupport interface to handle tasks like configuring environment variables, setting up native callbacks, and integrating custom tooling. You can also use an ISupport implementation for platform-specific setup and cleaning up resources at shutdown. Refer to Extend API layer functionality with ISupport.

    Import an API layer

    To import an API layer into your project, you need the layer's JSON manifest file and its associated native library file (.dll on Windows, .so on Android).

    When you import an API layer, Unity validates:

    • The JSON file exists and has a .json extension.
    • The JSON contains required fields: name, api_version, and library_path.
    • The library file exists at the specified path.
    • A layer with the same name and architecture doesn't already exist.
    • If any import validation fails, TryAdd returns false and logs an error message.

    Use the ApiLayers.TryAdd method to import a layer:

    public void AddLayer(string layerJsonPath, Architecture architecture, BuildTargetGroup targetGroup)
    {
        OpenXRSettings settings = OpenXRSettings.GetSettingsForBuildTargetGroup(targetGroup);
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            if (apiLayersFeature.apiLayers.TryAdd(layerJsonPath, architecture, targetGroup, out ApiLayers.ApiLayer layer))
            {
                Debug.Log($"Successfully imported layer: {layer.name}");
                Debug.Log($"  Description: {layer.description}");
                Debug.Log($"  API Version: {layer.apiVersion}");
            }
            else
            {
                Debug.LogError("Failed to import API layer");
            }
        }
    }
    

    Remove an API layer

    To remove an imported API layer, use the ApiLayers.TryRemove method:

    public void RemoveLayer(string layerName, Architecture architecture)
    {
        OpenXRSettings settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            if (apiLayersFeature.apiLayers.TryRemove(layerName, architecture))
            {
                Debug.Log($"Successfully removed layer: {layerName}");
            }
            else
            {
                Debug.LogWarning($"Layer not found: {layerName}");
            }
        }
    }
    
    Note

    Removing a layer deletes both the JSON manifest and library files from the project's API layers directory.

    Enable or disable API layers

    Control which imported layers are active using the ApiLayers.SetEnabled method:

    public void SetLayerEnabled(string layerName, bool enabled)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            // Enable a specific layer for current architecture.
            Architecture arch = RuntimeInformation.ProcessArchitecture;
            apiLayersFeature.apiLayers.SetEnabled(layerName, arch, enabled);
    
            // Check if a layer is enabled.
            bool isEnabled = apiLayersFeature.apiLayers.IsEnabled(layerName, arch);
            Debug.Log($"Layer {layerName} is enabled: {isEnabled}");
        }
    }
    
    Note

    Api Layers are a part of OpenXRSettings, so any state changes you make made such as enable or disable will persist until that layer is removed.

    Enable or disable for all architectures

    You can enable or disable a layer for all imported architectures:

    public void SetLayerEnabledAllArchitectures(string layerName, bool enabled)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            // Enable for all architectures.
            apiLayersFeature.apiLayers.SetEnabled(layerName, enabled);
    
            // Check if enabled for any architecture.
            bool isEnabledAny = apiLayersFeature.apiLayers.IsEnabled(layerName);
            Debug.Log($"Layer {layerName} is enabled for at least one architecture: {isEnabledAny}");
        }
    }
    

    Enable by ApiLayer instance

    You can also enable or disable using an ApiLayer instance:

    public void SetLayerEnabledWithInstance(ApiLayers.ApiLayer layer, bool enabled)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            apiLayersFeature.apiLayers.SetEnabled(layer, enabled);
        }
    }
    

    Reorder API layers

    The order of API layers determines the sequence in which they intercept OpenXR calls. Layers earlier in the collection intercept calls first.

    You can access layer properties and their indices through the read-only ApiLayers.collection property:

    #if UNITY_EDITOR
    var apiLayersFeature = settings.GetFeature<UnityEngine.XR.OpenXR.Features.ApiLayersFeature>();
    for (int i = 0; i < apiLayersFeature.apiLayers.collection.Count; i++)
    {
    var layer = apiLayersFeature.apiLayers.collection[i];
    Debug.Log($"Index {i}: {layer.name}");
    }
    #endif
    
    Note

    The collection maintains continuous indices from 0 to Count-1. When you move a layer, other layers shift positions automatically to maintain this continuous sequence. For example, if you start with a collection of layers, [A, B, C, D], and call SetIndex(0, 2) to move layer A to index 2, the final order is: [B, C, A, D].

    Reorder by index

    Use the ApiLayers.SetIndex method to change layer ordering:

    public void SetLayerIndex(int oldIndex, int newIndex)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            if (apiLayersFeature.apiLayers.SetIndex(oldIndex, newIndex))
            {
                Debug.Log("Successfully reordered layers");
            }
            else
            {
                Debug.LogError("Failed to reorder layers - invalid indices");
            }
        }
    }
    

    Reorder by name and architecture

    You can also reorder by specifying a layer name and architecture:

    public void SetLayerIndexWithNameAndArchitecture(string layerName, Architecture architecture, int newIndex)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            if (apiLayersFeature.apiLayers.SetIndex(layerName, architecture, newIndex))
            {
                Debug.Log($"Successfully moved {layerName} to index {newIndex}");
            }
        }
    }
    

    Reorder by ApiLayer instance

    You can also reorder by using the object instance of a layer:

    public void SetLayerIndexWithInstance(ApiLayers.ApiLayer layer, int newIndex)
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            apiLayersFeature.apiLayers.SetIndex(layer, newIndex);
        }
    }
    

    Access the API layers collection

    Access the collection of imported API layers through the ApiLayers.collection property.

    The collection is read-only. Use the management methods:

    • TryAdd
    • TryRemove
    • SetEnabled
    • SetIndex to modify the collection.
    void ListLayers()
    {
        OpenXRSettings settings = OpenXRSettings.ActiveBuildTargetInstance;
        ApiLayersFeature apiLayersFeature = settings.GetFeature<ApiLayersFeature>();
    
        if (apiLayersFeature != null)
        {
            Debug.Log($"Total layers: {apiLayersFeature.apiLayers.collection.Count}");
    
            for (int i = 0; i < apiLayersFeature.apiLayers.collection.Count; i++)
            {
                ApiLayers.ApiLayer layer = apiLayersFeature.apiLayers.collection[i];
                Debug.Log($"[{i}] {layer.name}");
                Debug.Log($"    Enabled: {layer.isEnabled}");
                Debug.Log($"    Architecture: {layer.libraryArchitecture}");
                Debug.Log($"    API Version: {layer.apiVersion}");
                Debug.Log($"    Implementation Version: {layer.implementationVersion}");
                Debug.Log($"    Description: {layer.description}");
                Debug.Log($"    Library Path: {layer.libraryPath}");
            }
        }
    }
    

    Extend API layer functionality with ISupport

    The ApiLayers.ISupport interface allows you to create custom support logic that integrates with the API layers lifecycle. This is useful for:

    • Configuring environment variables before layer initialization.
    • Setting up debug callbacks or logging systems.
    • Performing platform-specific setup required by certain layers

    Implement this interface when you need to:

    • Perform setup operations before the OpenXR instance is created.
    • Configure layer-specific logging or debugging features.
    • Clean up resources when the OpenXR instance is destroyed.
    • Integrate custom tooling with the API layers workflow.
        public class LayerSupportExample : ApiLayers.ISupport
        {
            [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
            static void RegisterSupport()
            {
                ApiLayersFeature.AddSupport(new LayerSupportExample());
            }
    
            public void Setup(System.IntPtr hookGetInstanceProcAddr)
            {
                Debug.Log("Setting up LayerSupportExample");
    #if UNITY_EDITOR
                OpenXRSettings openXRSettings = OpenXRSettings.Instance;
    #else
                OpenXRSettings openXRSettings = OpenXRSettings.ActiveBuildTargetInstance;
    #endif
                if (openXRSettings == null)
                    return;
    
                ApiLayersFeature apiLayersFeature = openXRSettings.GetFeature<ApiLayersFeature>();
                if (apiLayersFeature == null || !apiLayersFeature.enabled)
                    return;
    
    
                Architecture architecture = RuntimeInformation.ProcessArchitecture;
                if (!apiLayersFeature.apiLayers.IsEnabled("XR_LAYER_NAME_TO_SUPPORT", architecture))
                    return;
    
                // Do some custom setup here to support the layer.
            }
    
            public void Teardown(ulong xrInstance)
            {
                Debug.Log("Tearing down LayerSupportExample");
                // Do some custom teardown here to clean resources.
            }
        }
    

    Register an ISupport implementation

    Register your ISupport implementation during subsystem registration to ensure it's available when needed.

    The [RuntimeInitializeOnLoadMethod] attribute ensures your support class is registered before the OpenXR subsystem initializes.

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    static void RegisterSupport()
    {
        ApiLayersFeature.AddSupport(new LayerSupportExample());
    }
    
    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)