Skip to content

Instantly share code, notes, and snippets.

@DanMillerDev
Created March 14, 2025 21:20
Show Gist options
  • Save DanMillerDev/2a2dd5cf3f47ede3b8c1068134003d1f to your computer and use it in GitHub Desktop.
Save DanMillerDev/2a2dd5cf3f47ede3b8c1068134003d1f to your computer and use it in GitHub Desktop.
A script for managing permissions across Apple Vision Pro, Meta Quest and Android XR. It references world space UI element to let the user know about missing or denied permissions.
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using System.Collections.Generic;
using TMPro;
using UnityEngine.Android;
#if UNITY_VISIONOS
using UnityEngine.XR.VisionOS;
#endif
public class XRPermissions : MonoBehaviour
{
// meta quest
const string k_MetaScenePermissionId = "com.oculus.permission.USE_SCENE";
const string k_MetaHandPermissionId = "com.oculus.permission.HAND_TRACKING";
// android xr
const string k_AndroidXRSceneMinPermissionId = "android.permission.SCENE_UNDERSTANDING_COARSE";
const string k_AndroidXRSceneMaxPermissionId = "android.permission.SCENE_UNDERSTANDING_FINE";
const string k_AndroidXRHandPermissionId = "android.permission.HAND_TRACKING";
[SerializeField]
ARPlaneManager m_PlaneManager;
[SerializeField]
HandTrackingManager m_HandManager;
[SerializeField]
GameObject m_DeniedPermissionsPopup;
[SerializeField]
TMP_Text m_DeniedPermissionsText;
#if UNITY_VISIONOS
void OnEnable()
{
VisionOS.AuthorizationChanged += OnAuthorizationChanged;
}
void OnDisable()
{
VisionOS.AuthorizationChanged -= OnAuthorizationChanged;
}
void UpdateAuthorizationText()
{
var type = VisionOSAuthorizationType.HandTracking;
var status = VisionOS.QueryAuthorizationStatus(type);
OnAuthorizationChanged(new VisionOSAuthorizationEventArgs { type = type, status = status });
type = VisionOSAuthorizationType.WorldSensing;
status = VisionOS.QueryAuthorizationStatus(type);
OnAuthorizationChanged(new VisionOSAuthorizationEventArgs { type = type, status = status });
}
void OnAuthorizationChanged(VisionOSAuthorizationEventArgs args)
{
switch (args.type)
{
case VisionOSAuthorizationType.HandTracking:
if (args.status == VisionOSAuthorizationStatus.Denied)
{
m_DeniedPermissionsText.text += "Hand permission \n";
}
break;
case VisionOSAuthorizationType.WorldSensing:
if (args.status == VisionOSAuthorizationStatus.Denied)
{
m_DeniedPermissionsText.text += "Scene permission \n";
}
break;
// We do not support CameraAccess yet so ignore it
}
m_DeniedPermissionsPopup.SetActive(true);
}
#endif
void Start()
{
var permissions = new List<string>();
m_DeniedPermissionsText.text = "";
#if UNITY_META_QUEST
// add permissions that have not been granted by the user
if (!Permission.HasUserAuthorizedPermission(k_MetaScenePermissionId))
{
permissions.Add(k_MetaScenePermissionId);
}
else
{
// enable the AR Plane Manager component if permission is already granted
m_PlaneManager.enabled = true;
}
if (!Permission.HasUserAuthorizedPermission(k_MetaHandPermissionId))
{
permissions.Add(k_MetaHandPermissionId);
}
else
{
m_HandManager.enabled = true;
}
#elif UNITY_ANDROID_XR
// add permissions that have not been granted by the user
if(!Permission.HasUserAuthorizedPermission(k_AndroidXRSceneMinPermissionId))
{
permissions.Add(k_AndroidXRSceneMinPermissionId);
}
else
{
m_PlaneManager.enabled = true;
}
if(!Permission.HasUserAuthorizedPermission(k_AndroidXRHandPermissionId))
{
permissions.Add(k_AndroidXRHandPermissionId);
}
else
{
m_HandManager.enabled = true;
}
#elif UNITY_VISIONOS
UpdateAuthorizationText();
#endif
// setup callbacks to be called depending on whether permission is granted
var callbacks = new PermissionCallbacks();
callbacks.PermissionDenied += OnPermissionDenied;
callbacks.PermissionGranted += OnPermissionGranted;
Permission.RequestUserPermissions(permissions.ToArray(), callbacks);
}
void OnPermissionDenied(string permission)
{
// handle denied permission
Debug.LogError($"Permission {permission} was denied by the user");
// show a popup to inform the user that the permission is required
if(permission == k_MetaScenePermissionId || permission == k_AndroidXRSceneMinPermissionId)
{
m_DeniedPermissionsText.text += "Scene permission \n";
}
if(permission == k_MetaHandPermissionId || permission == k_AndroidXRHandPermissionId)
{
m_DeniedPermissionsText.text += "Hand permission \n";
}
m_DeniedPermissionsPopup.SetActive(true);
}
void OnPermissionGranted(string permission)
{
// enable the corresponding AR Manager component after required permission is granted
if (permission == k_MetaScenePermissionId || permission == k_AndroidXRSceneMinPermissionId)
{
m_PlaneManager.enabled = true;
}
if(permission == k_MetaHandPermissionId || permission == k_AndroidXRHandPermissionId)
{
m_HandManager.enabled = true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment