docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Persistent anchors

    This page is a supplement to the AR Foundation Persistent Anchors manual. The following sections only contain information about APIs where ARCore exhibits unique platform-specific behavior.

    Tip

    When developing an AR app, refer to both the AR Foundation documentation as well as the required packages for each platform you support.

    Persistent anchors for ARCore utilizes Google Cloud. To use persistent anchor functionality, you must first set up a Google Cloud project to store persistent anchor data. ARCore persistent anchors are subject to Usage quotas (Google's ARCore documentation).

    When working with persistent anchors, refer to ARCore's Best practices.

    Check for persistent anchor support

    You can use the following code to check whether your system supports persistent anchors:

    void CheckPersistentAnchorsSupport(ARAnchorManager manager)
    {
        var descriptor = manager.descriptor;
        if (descriptor.supportsSaveAnchor && descriptor.supportsLoadAnchor)
        {
            // Save and load anchors are both supported and enabled.
        }
    }
    

    Configure your project to use persistent anchors

    To use persistent anchors on ARCore, you must first authorize your application so that it can save anchor data to Google Cloud. Refer to the ARCore Use the ARCore API on Google Cloud documentation to understand how to set up authorization for your project.

    Once you have authorized your application, you can then set up your project to use persistent anchors. To configure your project to use persistent anchors:

    1. Follow Google's instructions to Create a Google Cloud project and enable ARCore APIs.
    2. In the Google ARCore settings of XR Plug-in Management, select Enable Cloud Anchors.
    3. Select the Authorization Type that matches the authorization you set up for your project on Google Cloud.
    4. If you used the API Key method, enter the API Key.
    5. If you used the Keyless method, follow the additional steps in Configure Keyless authentication.

    ARCore Settings
    ARCore Cloud Anchor settings.

    Configure Keyless authentication

    To configure your project to use persistent anchors using Keyless authentication, follow these additional steps:

    1. Navigate to the Player Settings (menu: Edit > Project Settings > Player) and in the Android tab, expand Publishing Settings.
    2. Under Publishing Settings, enable Custom Keystore.
    3. Use the Keystore Manager to create a new keystore as outlined in Create a new keystore.
    4. Establish appropriate OAuth2 credentials as outlined in the Create OAuth 2.0 client IDs section of Google's ARCore documentation. Ensure that the package name, and the keystore SHA1 fingerprint are exact, with no extra spaces or characters in the OAuth credentials setup fields.
    5. Use the command line tool to determine the fingerprint for OAuth credentials, as outlined in the How to obtain a signing fingerprint from a keystore section of Google's ARCore documentation.
    6. In Publishing Settings of Player Settings (menu: Edit > Project Settings > Player), select Custom Main Gradle Template.
    7. Modify the custom main gradle asset to add the dependent libraries from the Include required libraries section of Google's ARCore documentation into the appropriate dependencies block within gradle file.
    8. If Minify is selected, follow the steps within Google's ARCore documentation to create a proguard file, and add the ARCore auth-related packages to be kept in that file. In Publishing Settings of Player Settings, select Custom Proguard File and modify the asset with the keep lines.

    Feature map quality

    Feature map quality describes the quality of the visual features surrounding the anchor before it's saved. A higher quality indicates an anchor will yield greater success when trying to load it later.

    Check feature map quality

    Before saving an anchor, you should check the ArFeatureMapQuality is sufficient. To check the feature map quality, you can call EstimateFeatureMapQualityForHosting. Use the following code sample to check the ArFeatureMapQuality:

    void CheckQualityAndSaveAnchor(ARAnchorManager manager, ARAnchor anchor)
    {
        if (manager.subsystem is ARCoreAnchorSubsystem arCoreAnchorSubsystem)
        {
            var quality = ArFeatureMapQuality.AR_FEATURE_MAP_QUALITY_SUFFICIENT;
    
            XRResultStatus resultStatus = arCoreAnchorSubsystem.EstimateFeatureMapQualityForHosting(anchor.trackableId, ref quality);
    
            if (!resultStatus.IsSuccess())
            {
                // An error occurred while attempting to check the feature map quality.
                return;
            }
    
            if (quality == ArFeatureMapQuality.AR_FEATURE_MAP_QUALITY_INSUFFICIENT)
            {
                // Anchor map quality is insufficient. Save the anchor when the quality improves.
                return;
            }
        }
    
        // Proceed with saving the anchor
    }
    

    Improve feature map quality

    If the quality of the feature map is insufficient, prompt the user to move their device around to capture the anchor from different angles, and then try again.

    Anchor lifespan

    Persistent anchors stored on Google Cloud have an expiration. The anchors will only persist for as long as the provided lifespan. You can specify the lifespan of the anchor in TrySaveAnchorWithLifespanAsync. If you call TrySaveAnchorAsync, AR Foundation uses a default lifespan, as this method doesn't take a lifespan parameter. The default lifespans used are 1 day when using an API Key and 365 days when using keyless authorization.

    The following code demonstrates how to use TrySaveAnchorWithLifeSpanAsync to set the anchor's lifespan:

    async void TrySaveAnchorWithLifespanAsync(ARAnchorManager manager, ARAnchor anchor)
    {
        if (manager.subsystem is ARCoreAnchorSubsystem arCoreAnchorSubsystem)
        {
            // Save the anchor for 180 days
            var result = await arCoreAnchorSubsystem.TrySaveAnchorWithLifespanAsync(anchor.trackableId, 180);
    
            if (result.status.IsError())
            {
                // handle error
                return;
            }
    
            // Save this value, then use it as an input parameter
            // to TryLoadAnchorAsync or TryEraseAnchorAsync
            SerializableGuid guid = result.value;
        }
    }
    

    Native status code

    The native status code for a save or load operation should be interpreted as an ArCloudAnchorState, unless if the operation is cancelled, in which case the native status code is an ArFutureState.

    The following code demonstrates how to check the native status code when the native status code is an ArCloudAnchorState:

    async void LoadAndCheckNativeStatusCode(ARAnchorManager manager, SerializableGuid anchorId)
    {
        var result = await manager.TryLoadAnchorAsync(anchorId);
    
        // Interpreting the status code
        var cloudAnchorState = (ArCloudAnchorState)result.status.nativeStatusCode;
        switch (cloudAnchorState)
        {
            case ArCloudAnchorState.AR_CLOUD_ANCHOR_STATE_SUCCESS:
                // Load was successful
                break;
            case ArCloudAnchorState.AR_CLOUD_ANCHOR_STATE_ERROR_NOT_AUTHORIZED:
                // Authorization to Google Cloud failed.
                // As a developer, ensure that you have a Google Cloud project and that you have
                // authorized your application with an API Key or with Keyless authorization.
                break;
            case ArCloudAnchorState.AR_CLOUD_ANCHOR_STATE_ERROR_RESOURCE_EXHAUSTED:
                // Google Cloud resource exhausted. Ensure that your Google Cloud project has enough
                // resources to support your application's needs.
                break;
            case ArCloudAnchorState.AR_CLOUD_ANCHOR_STATE_ERROR_CLOUD_ID_NOT_FOUND:
                // Anchor was not found. You may have specified the wrong anchor ID, or the anchor
                // may have expired on the server.
                break;
            default:
                break;
        }
    }
    

    The following code demonstrates how to check the native status code when the native status code is an ArFutureState:

    async void CancelAndCheckNativeStatusCode(ARAnchorManager manager, SerializableGuid anchorId)
    {
        // Create a CancellationTokenSource to serve our CancellationToken
        var cts = new CancellationTokenSource();
    
        // Try to load an anchor
        var awaitable = manager.TryLoadAnchorAsync(anchorId, cts.Token);
    
        // Cancel the async operation before it completes
        cts.Cancel();
    
        // Wait for and obtain the result from TryLoadAnchorAsync
        var result = await awaitable;
    
        // Interpreting the status code.
        // The nativeStatusCode is an ArFutureState because the operation was cancelled.
        var futureState = (ArFutureState)result.status.nativeStatusCode;
        switch (futureState)
        {
            case ArFutureState.AR_FUTURE_STATE_DONE:
                // The operation is complete and the result is available.
                break;
            case ArFutureState.AR_FUTURE_STATE_CANCELLED:
                // The operation has been cancelled.
                break;
            case ArFutureState.AR_FUTURE_STATE_PENDING:
                // The operation is still pending.
                break;
            default:
                break;
        }
    }
    
    In This Article
    Back to top
    Copyright © 2025 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)