Checking for AR availability BEFORE launching AR scene?

I am trying to build some logic to test the device after app start to decide whether to allow for AR scene or only conventional 3D scene.
I know we can use ARSubsystemManager.systemState to check that but this works only when AR Session component is present in the scene, which means that there needs to be an attempt to initialize AR Session.
This is pretty expensive task that I would like to avoid straight after launching the app.

Is there any way around?

Checkout ARSubsystemManager.checkAvailability(). It is meant to be run as a coroutine (see ARSession.Initialize for an example).

On Android, the availability check can take several frames because if ARCore is not installed already (or the app the requires a newer version of ARCore), then it has to check with the Play Store to see if there is a version of ARCore which supports that particular device.

Note that when deploying an ARCore required app from Unity (e.g., click ā€œBuild and Runā€), unsupported devices will be reported as supported because the Play Store would not have allowed the app to be installed on an unsupported device in the first place.

Thanks Tim, I tried ARSubsystemManager.checkAvailability() in a coroutine but is doesn’t work unless AR Session is initilized - systemState is returning ā€œUnsupportedā€. When checking systemState in AR-enabled scene it works ok.

I guess it is due to these lines of code inside ARSubsystemManager.checkAvailability():

            if (sessionSubsystem == null)
            {
                systemState = ARSystemState.Unsupported;
            }

For me this means you need to try to initialize AR Session first to check whether it will work.
Of course I am considering this for an ā€œAR-optionalā€ app, where depending on the device compatibility the user is given either 3D-only or 3D+AR options.

You’ll need to call ARSubsystemManager.CreateSubsystems() before you check availability (basically copy what ARSession.OnEnable does).

Ended up doing like you said, thanks!

Hi @Saicopate , would you be willing to share what you did to establish AR availability? Thx!

1 Like

Sure.
I run this at the start of non-AR scene (replace Debug.Log with your own implementation).

private void OnEnable()
    {
        ARSubsystemManager.CreateSubsystems();
        StartCoroutine(ARSubsystemManager.CheckAvailability());
        StartCoroutine(AllowARScene());
    }

IEnumerator AllowARScene()
    {
        while (true)
        {
            while (ARSubsystemManager.systemState == ARSystemState.CheckingAvailability ||
                ARSubsystemManager.systemState == ARSystemState.None)
            {
                Debug.Log("Waiting...");
                yield return null;
            }
            if (ARSubsystemManager.systemState == ARSystemState.Unsupported)
            {
                Debug.Log("AR unsupported");
                yield break;
            }
            if (ARSubsystemManager.systemState > ARSystemState.CheckingAvailability)
            {
                Debug.Log("AR supported");
                yield break;
            }
        }      
    }
4 Likes

Hi
Implemented the solution above… appears to be working thanks @Saicopate && @tdmowrer

One question… if using this check in non AR main menu… should I use

ARSubsystemManager.DestroySubsystems()

… after I have completed the check and before I load into my AR scene? as per ARSession?

Or will these subsystems get destroyed gracefully when I unload the main menu scene and load the new AR scene?

Thanks

You shouldn’t need to destroy it in your case since you are about to start an AR scene. It is safe to call ARSubsystemManager.CreateSubsystems() multiple times (the second time is effectively a no-op).

If you did not immediately start your AR scene, then you might want to call DestroySubsystems just to make sure you cleanly shut down the AR session.

2 Likes

hey @tdmowrer

I have my ARCore Optional app working on devices that do not support arcore etc. And use the above logic to enable AR within my game.

How would I do same for IOS? Such that my app will be made available to all devices running target IOS ver 11… whether they support ARKit or not… and then allow the logic above to control enabling/disabling AR within my game.

Thanks

There is a similar setting for ARKit, see the ā€œARKit Requiredā€ section of https://docs.unity3d.com/Packages/com.unity.xr.arkit@1.0/manual/index.html#creating-a-arkitsettings-asset

I don’t appear to have that option… Unity 2018.2.6 ARKit preview 17…? Was it introduced in newer version?

Any way to override in xCode? ie. make ARKit optional?

Thanks

I believe it was added in a later version. 2018.2 is no longer supported, so you’d need to upgrade to 2018.3 to be able to use this feature. Alternatively, you can manually set it in Xcode; see https://developer.apple.com/documentation/arkit/verifying_device_support_and_user_permission?language=objc

1 Like

How can we update this to work in Unity 2019? ARSubsystemManager and ARSystemState no longer seems to exist.

See https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@2.1/manual/index.html and search for ā€œChecking for Device Supportā€.

1 Like

Hello,

I tried the ā€œChecking for Device Supportā€ available in the documentation of AR Foundation package. It works in case of supported devices, but in case of unsupported devices it throws below exception and the ARSession.state gets set to ā€˜None’:

E/Unity: DllNotFoundException: UnityARCore
at (wrapper managed-to-native) UnityEngine.XR.ARCore.ARCoreSessionSubsystem+NativeApi.UnityARCore_session_construct(UnityEngine.XR.ARCore.ARCoreSessionSubsystem/NativeApi/CameraPermissionRequestProviderDelegate)
at UnityEngine.XR.ARCore.ARCoreSessionSubsystem+Provider…ctor (UnityEngine.XR.ARCore.ARCoreSessionSubsystem subsystem) [0x0000d] in <6d08a2168eb04129816197a2388b8f39>:0
at UnityEngine.XR.ARCore.ARCoreSessionSubsystem.CreateProvider () [0x00000] in <6d08a2168eb04129816197a2388b8f39>:0
at UnityEngine.XR.ARSubsystems.XRSessionSubsystem…ctor () [0x00006] in <9721d2a78fbe4e8db7471dffc3f5f1ba>:0
at UnityEngine.XR.ARCore.ARCoreSessionSubsystem…ctor () [0x00000] in <6d08a2168eb04129816197a2388b8f39>:0
at (wrapper managed-to-native) System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod,object,object[ ],System.Exception&)
at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[ ] parameters) [0x00002] in <c044b3

I am using Unity 2019.1.11, AR Foundation 2.1.1 and I am checking it using below co routine:

private IEnumerator CheckAvailability()
{
   Debug.Log("ARSession.state: " + ARSession.state);
   if ((ARSession.state == ARSessionState.None) ||
      (ARSession.state == ARSessionState.CheckingAvailability))
   {
      ShowErrorMessage("Started Checking Availability...");
      yield return ARSession.CheckAvailability();
   }

   Debug.Log("ARSession.state: " + ARSession.state);
   switch (ARSession.state)
   {
       case ARSessionState.Ready:
           Debug.Log("Supported and installed");
           LoadARCoreScene();
           break;
       case ARSessionState.NeedsInstall:
           Debug.Log("Supported, not installed, requesting installation");
           LoadARCoreScene();
           break;
       case ARSessionState.Installing:
           Debug.Log("Supported apk installing");
           LoadARCoreScene();
           break;
       default:
           Debug.Log("Unsupported Device Not Capable");
           LoadNonARCoreScene();
           break;
   }
}

@tdmowrer : What am I doing wrong? Please help.

Guys please help. Am I missing anything here?

hey @thesanketkale
I found signing up to ARSession.stateChanged += ARState; at start worked well for me, also running coroutine CheckARSupportedByMobile at start. hope it helps, cheers

IEnumerator CheckARSupportedByMobile()
    {
        Debug.Log("State " + ARSession.state);

        if ((ARSession.state == ARSessionState.None || ARSession.state == ARSessionState.CheckingAvailability))
        {
            Debug.Log("Checking AR Availability on mobile device");
            yield return ARSession.CheckAvailability();
        }
    }

    public void ARState(ARSessionStateChangedEventArgs e)
    {
        switch (ARSession.state)
        {
            case ARSessionState.None:
            case ARSessionState.CheckingAvailability:
                Debug.Log("AR Session - Looking for availability");
                break;
            case ARSessionState.Unsupported:
                Debug.Log("AR Session - not available to this mobile device");
                break;
            case ARSessionState.NeedsInstall:
                m_Session.enabled = true;
                Debug.Log("AR Session - needs to be installed in mobile device ");
                break;
            case ARSessionState.Installing:
                m_Session.enabled = true;
                Debug.Log("AR Session - Installing AR onto mobile device ");
                break;
            case ARSessionState.Ready:
                m_Session.enabled = true;
                Debug.Log("AR Session - supported by mobile device and ready to fire up ");
                break;
            case ARSessionState.SessionInitializing:
                m_Session.enabled = true;
                Debug.Log("AR session is initializing ");
                break;
            case ARSessionState.SessionTracking:
                Debug.Log("AR Session is tracking");
                break;
            default:
                Debug.Log("AR Session - no switch worked");
                break;
        }
    }

Hi @Tarrag ,

Firstly I must say, thank you for replying. Just after your response, I thought that if the same code was working for you, I must have been doing something wrong in my splash scene or player settings. That’s where I figured out that I had added ARSession prefab in my splash screen scene where I was checking the ARCore availability. I had added it thinking that while using ARSession.CheckAvailability() the ARSession object might need initialization via a gameobject in the scene. But apparently I was mistaken as CheckAvailability() being a static coroutine, does not need the ARSession to be initialized. The ARSession script on the ARSession prefab in the scene was actually throwing the exception and not ARSession.CheckAvailability().

Having removed the ARSession prefab from the splash screen, the ARSession.CheckAvailability() is setting the correct ARSessionState now. Thanks again for the reply.

Regards,
Sanket.

1 Like

I am getting unsupported when ground plane works… does this work with vuforia? I’m trying to use arfoundation just to check if the device has arcore, becuase vuforia’s
VuforiaRuntimeUtilities.GetActiveFusionProvider isn’t working either…
I’m desperate here…