AR Foundation Remote | Test and debug your AR project in the Editor

Can you please tell me the AR Foundation Remove version? Input System (New) is only supported in AR Foundation Remove 2.0, this can explain why input remoting doesn’t work for you as expected.
Can you please also check if the input remoting works in examples that come with the plugin? You can import examples from the ‘Plugins/AR Foundation Remove/Installer’.

1 Like

Hi! I’m having a similar issue. Did you find a solution?

Thanks,
Jonathan

1 Like

Are you able to build your app regularly without the remote plugin?
If nothing helps, try pressing Assets-Reimport All (this may take a while).

1 Like

My app is building fine. I tried to reimport my assets but that didn’t work. What ended up working (I think) was cleaning my build folder in Xcode. It took awhile but I finally got there. Thanks for replying!

2 Likes

I’m experiencing an issue with ARFoundationRemote while developing an AR application.
When I try to save an ARWorldMap, load it, and then apply it to the session using the ApplyWorldMap method, I encounter a NullReferenceException under specific circumstances.

Situation:

Using ARFoundationRemote with Unity Editor:
I run the app using the Unity Editor and ARFoundationRemote to test on an iOS device.
When I do this, I receive a NullReferenceException when ApplyWorldMap is called.
Building and Running Directly on the Device:
When I build the app and run it directly on the iOS device (without using ARFoundationRemote), the same code works fine without any errors.

Expected Behavior:

I expect ApplyWorldMap to work without errors when using ARFoundationRemote with the Unity Editor to test on the device.

Error Message:

AR Foundation Remote Companion App: Exception: NullReferenceException: Object reference not set to an instance of an object.

ARFoundationRemote.Runtime.WorldMapSender+<getWorldMapCoroutine>d__8.MoveNext () (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.DontDestroyOnLoadSingleton+<countCoroutinesNumber>d__4.MoveNext () (at <00000000000000000000000000000000>:0)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <00000000000000000000000000000000>:0)
UnityEngine.MonoBehaviour.StartCoroutineManaged2_Injected (System.IntPtr _unity_self, System.Collections.IEnumerator enumerator) (at <00000000000000000000000000000000>:0)
UnityEngine.MonoBehaviour.StartCoroutineManaged2 (System.Collections.IEnumerator enumerator) (at <00000000000000000000000000000000>:0)
UnityEngine.MonoBehaviour.StartCoroutine (System.Collections.IEnumerator routine) (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.DontDestroyOnLoadSingleton.AddCoroutine (System.Collections.IEnumerator routine, System.String name) (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.WorldMapSender.dataReceived (ARFoundationRemote.Runtime.WorldMapDataEditor worldMapData) (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.XRCpuImagePlaneSerializable.ToString () (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.TelepathyConnection+<>c__DisplayClass25_0`1[T].<ARFoundationRemote.Runtime.IConnection.Register>b__0 (System.Object data) (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.XRCpuImagePlaneSerializable.ToString () (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.TelepathyConnection.processIncomingMessage (System.Object message) (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.TelepathyConnection.processIncomingMessages () (at <00000000000000000000000000000000>:0)
ARFoundationRemote.Runtime.TelepathyConnection+<processIncomingMessagesCor>d__17.MoveNext () (at <00000000000000000000000000000000>:0)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <00000000000000000000000000000000>:0)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
ARFoundationRemote.Runtime.DontDestroyOnLoadSingleton:AddCoroutine(IEnumerator, String)
ARFoundationRemote.Runtime.WorldMapSender:dataReceived(WorldMapDataEditor)
ARFoundationRemote.Runtime.XRCpuImagePlaneSerializable:ToString()
ARFoundationRemote.Runtime.<>c__DisplayClass25_0`1:<ARFoundationRemote.Runtime.IConnection.Register>b__0(Object)
ARFoundationRemote.Runtime.XRCpuImagePlaneSerializable:ToString()
ARFoundationRemote.Runtime.TelepathyConnection:processIncomingMessage(Object)
ARFoundationRemote.Runtime.TelepathyConnection:processIncomingMessages()
ARFoundationRemote.Runtime.<processIncomingMessagesCor>d__17:MoveNext()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

UnityEngine.Debug:LogError (object)
ARFoundationRemote.RuntimeEditor.Receiver/<>c:<OnEnable>b__4_2 (ARFoundationRemote.Runtime.CompanionAppError) (at ./Library/PackageCache/com.kyrylokuzyk.arfoundationremote/RuntimeEditor/Receiver/Receiver.cs:71)
ARFoundationRemote.Runtime.TelepathyConnection/<>c__DisplayClass25_0`1<ARFoundationRemote.Runtime.CompanionAppError>:<ARFoundationRemote.Runtime.IConnection.Register>b__0 (object) (at ./Library/PackageCache/com.kyrylokuzyk.arfoundationremote/Runtime/Connection/TelepathyConnection.cs:183)
ARFoundationRemote.Runtime.TelepathyConnection:processIncomingMessage (object) (at ./Library/PackageCache/com.kyrylokuzyk.arfoundationremote/Runtime/Connection/TelepathyConnection.cs:160)
ARFoundationRemote.Runtime.TelepathyConnection:processIncomingMessages () (at ./Library/PackageCache/com.kyrylokuzyk.arfoundationremote/Runtime/Connection/TelepathyConnection.cs:123)
ARFoundationRemote.Runtime.TelepathyConnection/<processIncomingMessagesCor>d__17:MoveNext () (at ./Library/PackageCache/com.kyrylokuzyk.arfoundationremote/Runtime/Connection/TelepathyConnection.cs:99)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

Environment:

Unity Version: 6000.0.23f1
AR Foundation Version: 6.0.3
ARKit XR Plugin Version: 6.0.3
ARFoundationRemote Version: 2.0.39

Minimal Code Example:

#if UNITY_EDITOR
using ARKitSessionSubsystem = ARFoundationRemote.Runtime.SessionSubsystem;
using ARWorldMapRequest = ARFoundationRemote.Runtime.ARWorldMapRequest;
using ARWorldMap = ARFoundationRemote.Runtime.ARWorldMapRemote;
using UnityEngine.XR.ARSubsystems;
#else
using UnityEngine.XR.ARKit;
#endif

using UnityEngine;
using UnityEngine.XR.ARFoundation;
using Unity.Collections;
using System.IO;
using System.Collections;

public class ARWorldMapSaverLoader : MonoBehaviour
{
    public ARSession arSession;

    void Start()
    {
        StartCoroutine(SaveAndLoadARWorldMap());
    }

    IEnumerator SaveAndLoadARWorldMap()
    {
        // Save the ARWorldMap
        yield return Save();

        // Wait a bit
        yield return new WaitForSeconds(1f);

        // Load and apply the ARWorldMap
        LoadARWorldMap();
    }

    IEnumerator Save()
    {
        var sessionSubsystem = (ARKitSessionSubsystem)arSession.subsystem;
        if (sessionSubsystem == null)
        {
            Debug.LogError("ARKitSessionSubsystem not found.");
            yield break;
        }

        var request = sessionSubsystem.GetARWorldMapAsync();
        while (!request.status.IsDone())
        {
            yield return null;
        }

        if (request.status == ARWorldMapRequestStatus.Success)
        {
            ARWorldMap worldMap;

#if UNITY_EDITOR
            worldMap = request.GetWorldMap();
#else
            worldMap = request.GetWorldMap();
#endif

            if (worldMap.valid)
            {
                SaveWorldMap(worldMap);
                Debug.Log("ARWorldMap saved.");
            }
            else
            {
                Debug.LogError("The obtained ARWorldMap is invalid.");
            }
        }
        else
        {
            Debug.LogError("ARWorldMap request failed.");
        }
    }

    void SaveWorldMap(ARWorldMap worldMap)
    {
        if (worldMap.valid)
        {
            string path = Path.Combine(Application.persistentDataPath, "arworldmap.worldmap");
            var data = worldMap.Serialize(Allocator.Temp);
            File.WriteAllBytes(path, data.ToArray());
            data.Dispose();
            Debug.Log("ARWorldMap saved at: " + path);
        }
        else
        {
            Debug.LogError("Invalid ARWorldMap.");
        }
    }

    void LoadARWorldMap()
    {
        string path = Path.Combine(Application.persistentDataPath, "arworldmap.worldmap");
        if (!File.Exists(path))
        {
            Debug.Log("No ARWorldMap found at: " + path);
            return;
        }

        Debug.Log("Loading ARWorldMap data from: " + path);
        var data = File.ReadAllBytes(path);
        var nativeArray = new NativeArray<byte>(data.Length, Allocator.Temp);
        nativeArray.CopyFrom(data);

        ARWorldMap worldMap;

        if (ARWorldMap.TryDeserialize(nativeArray, out worldMap))
        {
            Debug.Log("Successfully deserialized ARWorldMap.");
            nativeArray.Dispose();

            if (worldMap.valid)
            {
                Debug.Log("worldMap is valid. Calling ApplyWorldMap.");
                ApplyWorldMap(worldMap);
                Debug.Log("ARWorldMap loaded from: " + path);
            }
            else
            {
                Debug.LogError("The loaded ARWorldMap is invalid.");
            }
        }
        else
        {
            Debug.LogError("Failed to deserialize ARWorldMap.");
            nativeArray.Dispose();
        }
    }

    void ApplyWorldMap(ARWorldMap worldMap)
    {
        Debug.Log("Executing ApplyWorldMap.");

        if (!worldMap.valid)
        {
            Debug.LogError("worldMap is invalid.");
            return;
        }

        var sessionSubsystem = arSession.subsystem as ARKitSessionSubsystem;
        if (sessionSubsystem == null)
        {
            Debug.LogError("ARKitSessionSubsystem not found.");
            return;
        }

        try
        {
            Debug.Log("Calling sessionSubsystem.ApplyWorldMap.");
            sessionSubsystem.ApplyWorldMap(worldMap);
            Debug.Log("ARWorldMap applied to the session.");
        }
        catch (System.Exception e)
        {
            Debug.LogError("Exception occurred during ApplyWorldMap: " + e.Message);
        }
    }
}

Questions:

Is this error due to limitations of ARFoundationRemote when using it with the Unity Editor and testing on a device?
Is there a way to use ApplyWorldMap with ARFoundationRemote without encountering this error?
Are there any workarounds or settings I can adjust to resolve this issue?

1 Like

Thank you for the detailed report on the issue!
Please give me some time to investigate.

1 Like

@KyryloKuzyk
By adding yield return new WaitForSeconds(); and waiting a bit before processing, the errors were resolved.

IEnumerator SaveAndLoadARWorldMap()
{
    yield return new WaitForSeconds(5f);

    // Save the ARWorldMap
    yield return Save();

    // Wait a bit
    yield return new WaitForSeconds(1f);

    // Load and apply the ARWorldMap
    LoadARWorldMap();
}

However, when I used it in the actual project, the saved GameObject’s position didn’t match the loaded GameObject’s position, causing a misalignment in the real-world display position of the GameObject. When using a lower Unity version, the saved GameObject’s position matched the loaded GameObject’s position, and the processing worked as expected.

Environment

Unity Version: 2022.3.51f1
AR Foundation Version: 5.1.5
ARKit XR Plugin Version: 5.1.5
ARFoundationRemote Version: 2.0.39
Although I couldn’t identify the cause, I decided to use Unity 2022. Thank you for your assistance.

It’s just my review for the asset.

Fast AR Developing is Here! This is the great additional tool to XR Simulation provided by Unity. Current Modern Pipeline:

  • Unity XR Simulation to Build Prototype in the Editor.
  • AR Foundation to catch the Real-time Bugs using Unity Editor! Without Building!

Hey makaka-org, you seem to know a lot. I’m an old SW Engineer but new in VR/AR . Currently I’m learning Google Geospatial API/Creator. Is “AR Foundation Remote” useful for me? What version do you recommend 2.0 or 1.0?

My plugin doesn’t currently support Google Geospatial API, unfortunately. It only supports Cloud Anchors for now.

1 Like

Thanks for your time and super fast response. Your Plug In is Awesome, and you are an AMAZING Developer! Have a great 2025!!!

1 Like

Hey!

I am trying to use ARFoundationRemote2.0 and after using Anchors in the scene, I get this error in the companion app

Exception: InvalidOperationException: Cannot remove an anchor from a disabled anchor manager.

UnityEngine.XR.ARFoundation.ARAnchorManager.TryRemoveAnchor (UnityEngine.XR.ARFoundation.ARAnchor anchor) (at <00000000000000000000000000000000>:0)

UnityEngine.XR.ARFoundation.ARAnchor.OnDisable () (at<00000000000000000000000000000000>:0)

every time I quit my app. The errors do not show up in the editor. It happens once per anchor, so if I have N anchors in scene there are N exceptions printed.

It doesnt impact functionality per se but it means I have to restart the companion app to clear the log which is annoying.

EDIT:

Instructions of how to safely use ARAnchors so they don’t show up would be great. I use


 if (currentFloorAnchor) arAnchorManager.TryRemoveAnchor(currentFloorAnchor);

if (arAnchorManager.descriptor.supportsTrackableAttachments)
{
currentFloorAnchor = arAnchorManager.AttachAnchor(plane, new Pose(plane.transform.position, plane.transform.rotation));
}

Basically I want the ARAnchor to be on the latest floor I see all the time. i have to throttle this to not get error calls from ARFoundationRemote but it works fine.

I’ve tried removing it manually in OnApplicationQuit but no luck. Would be great if I could understand how to not get the errors in the companion app :slight_smile:

I’m having the same problem.

In ARFoundationRemote environment, android build Logcat is throwing “Exception: InvalidOperationException: Cannot remove an anchor from a disabled anchor manager.” error.

It comes when the application exits and

removes itself (Anchor) from the AnchorManager when the Anchor is disabled.

I’m getting an error in the process, so I’ve tried

Destroy, Disable, Remove the Anchor from the OnApplicationQuit event and Destory myself, but that didn’t work.

Has anyone solved this problem?

Thanks in advance for any help.

1 Like

Hey @CAwesome, @worktpwls, thanks for reporting the issue with “InvalidOperationException: Cannot remove an anchor from a disabled anchor manager.”.

This error comes from the AR Foundation because ARCore Extensions try to remove anchors after the ARAnchorManager is disabled, which is not allowed by AR Foundation. My plugin only surfaces the problem by displaying the error.

To fix the error correctly, the Google team should fix the issue in the ARCore Extensions repo and not remove the anchors after ARAnchorManager is disabled. I hope that helps.

1 Like

I’m using this with Multiplayer Play Mode which launches multiple instances of the client on the same machine, and unfortunately all of the clients are connecting to the foundation remote when I hit Play. They’re all competing so the video flicks between them all randomly. I want just the first client to connect and all the other clients not to use remote at all, I’ve got a script that checks the Multiplayer Play Mode Tags and enables an AR simulator instead.

Is it possible to disable the behaviour of automatically starting the remote when we press play and instead invoke that through code? Or is it possible to switch off the remote in code?

Also, incidentally is it possible to subscribe to a callback when the AR Remote times out due to the app not running etc, so I can then display an error message and switch to my simulator as a fallback?

Yes, you can disable the plugin by disabling the provider in the “XR Plugin Management” window. I’m not familiar with Multiplayer Play Mode, but I assume it launches multiple instances of Unity Editor, so it should be possible to disable the plugin in other instances.

There is an ARFoundationRemoteUtils.isConnected API that you can use to know if the companion app is currently connected. But there is no dedicated API to check for the timeout.