Search Unity

Checking for AR availability BEFORE launching AR scene?

Discussion in 'Handheld AR' started by Saicopate, Nov 5, 2018.

  1. Saicopate

    Saicopate

    Joined:
    Sep 25, 2017
    Posts:
    58
    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?
     
  2. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
    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.
     
  3. Saicopate

    Saicopate

    Joined:
    Sep 25, 2017
    Posts:
    58
    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():

    Code (CSharp):
    1.             if (sessionSubsystem == null)
    2.             {
    3.                 systemState = ARSystemState.Unsupported;
    4.             }
    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.
     
  4. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
    You'll need to call ARSubsystemManager.CreateSubsystems() before you check availability (basically copy what ARSession.OnEnable does).
     
  5. Saicopate

    Saicopate

    Joined:
    Sep 25, 2017
    Posts:
    58
    Ended up doing like you said, thanks!
     
  6. christougher

    christougher

    Joined:
    Mar 6, 2015
    Posts:
    413
    Hi @Saicopate, would you be willing to share what you did to establish AR availability? Thx!
     
    newguy123 likes this.
  7. Saicopate

    Saicopate

    Joined:
    Sep 25, 2017
    Posts:
    58
    Sure.
    I run this at the start of non-AR scene (replace Debug.Log with your own implementation).

    Code (CSharp):
    1.    
    2. private void OnEnable()
    3.     {
    4.         ARSubsystemManager.CreateSubsystems();
    5.         StartCoroutine(ARSubsystemManager.CheckAvailability());
    6.         StartCoroutine(AllowARScene());
    7.     }
    8.  
    9. IEnumerator AllowARScene()
    10.     {
    11.         while (true)
    12.         {
    13.             while (ARSubsystemManager.systemState == ARSystemState.CheckingAvailability ||
    14.                 ARSubsystemManager.systemState == ARSystemState.None)
    15.             {
    16.                 Debug.Log("Waiting...");
    17.                 yield return null;
    18.             }
    19.             if (ARSubsystemManager.systemState == ARSystemState.Unsupported)
    20.             {
    21.                 Debug.Log("AR unsupported");
    22.                 yield break;
    23.             }
    24.             if (ARSubsystemManager.systemState > ARSystemState.CheckingAvailability)
    25.             {
    26.                 Debug.Log("AR supported");
    27.                 yield break;
    28.             }
    29.         }      
    30.     }
    31.  
     
    sameel and christougher like this.
  8. GreeneMachine

    GreeneMachine

    Joined:
    Jul 3, 2015
    Posts:
    126
    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

    Code (CSharp):
    1. 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
     
  9. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
    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.
     
    GreeneMachine likes this.
  10. GreeneMachine

    GreeneMachine

    Joined:
    Jul 3, 2015
    Posts:
    126
    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
     
  11. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
    There is a similar setting for ARKit, see the "ARKit Required" section of https://docs.unity3d.com/Packages/c...ual/index.html#creating-a-arkitsettings-asset
     
  12. GreeneMachine

    GreeneMachine

    Joined:
    Jul 3, 2015
    Posts:
    126
  13. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
    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/documen...ice_support_and_user_permission?language=objc
     
    GreeneMachine likes this.
  14. christougher

    christougher

    Joined:
    Mar 6, 2015
    Posts:
    413
    How can we update this to work in Unity 2019? ARSubsystemManager and ARSystemState no longer seems to exist.
     
  15. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    518
  16. thesanketkale

    thesanketkale

    Joined:
    Dec 14, 2016
    Posts:
    16
    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:

    Code (CSharp):
    1. private IEnumerator CheckAvailability()
    2. {
    3.    Debug.Log("ARSession.state: " + ARSession.state);
    4.    if ((ARSession.state == ARSessionState.None) ||
    5.       (ARSession.state == ARSessionState.CheckingAvailability))
    6.    {
    7.       ShowErrorMessage("Started Checking Availability...");
    8.       yield return ARSession.CheckAvailability();
    9.    }
    10.  
    11.    Debug.Log("ARSession.state: " + ARSession.state);
    12.    switch (ARSession.state)
    13.    {
    14.        case ARSessionState.Ready:
    15.            Debug.Log("Supported and installed");
    16.            LoadARCoreScene();
    17.            break;
    18.        case ARSessionState.NeedsInstall:
    19.            Debug.Log("Supported, not installed, requesting installation");
    20.            LoadARCoreScene();
    21.            break;
    22.        case ARSessionState.Installing:
    23.            Debug.Log("Supported apk installing");
    24.            LoadARCoreScene();
    25.            break;
    26.        default:
    27.            Debug.Log("Unsupported Device Not Capable");
    28.            LoadNonARCoreScene();
    29.            break;
    30.    }
    31. }
    @tdmowrer : What am I doing wrong? Please help.
     
    Last edited: Jul 23, 2019
  17. thesanketkale

    thesanketkale

    Joined:
    Dec 14, 2016
    Posts:
    16
    Guys please help. Am I missing anything here?
     
  18. Tarrag

    Tarrag

    Joined:
    Nov 7, 2016
    Posts:
    108
    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

    Code (CSharp):
    1. IEnumerator CheckARSupportedByMobile()
    2.     {
    3.         Debug.Log("State " + ARSession.state);
    4.  
    5.         if ((ARSession.state == ARSessionState.None || ARSession.state == ARSessionState.CheckingAvailability))
    6.         {
    7.             Debug.Log("Checking AR Availability on mobile device");
    8.             yield return ARSession.CheckAvailability();
    9.         }
    10.     }
    11.  
    12.     public void ARState(ARSessionStateChangedEventArgs e)
    13.     {
    14.         switch (ARSession.state)
    15.         {
    16.             case ARSessionState.None:
    17.             case ARSessionState.CheckingAvailability:
    18.                 Debug.Log("AR Session - Looking for availability");
    19.                 break;
    20.             case ARSessionState.Unsupported:
    21.                 Debug.Log("AR Session - not available to this mobile device");
    22.                 break;
    23.             case ARSessionState.NeedsInstall:
    24.                 m_Session.enabled = true;
    25.                 Debug.Log("AR Session - needs to be installed in mobile device ");
    26.                 break;
    27.             case ARSessionState.Installing:
    28.                 m_Session.enabled = true;
    29.                 Debug.Log("AR Session - Installing AR onto mobile device ");
    30.                 break;
    31.             case ARSessionState.Ready:
    32.                 m_Session.enabled = true;
    33.                 Debug.Log("AR Session - supported by mobile device and ready to fire up ");
    34.                 break;
    35.             case ARSessionState.SessionInitializing:
    36.                 m_Session.enabled = true;
    37.                 Debug.Log("AR session is initializing ");
    38.                 break;
    39.             case ARSessionState.SessionTracking:
    40.                 Debug.Log("AR Session is tracking");
    41.                 break;
    42.             default:
    43.                 Debug.Log("AR Session - no switch worked");
    44.                 break;
    45.         }
    46.     }
     
  19. thesanketkale

    thesanketkale

    Joined:
    Dec 14, 2016
    Posts:
    16
    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.
     
    Tarrag likes this.