众所周知,Android 运行时权限很麻烦,在您的情况下,问题是 Android 的权限请求 UI 面板在您的第一个 Permission.RequestUserPermission 上抢占了前台,暂停了您的应用程序并阻止执行以下代码
到目前为止,我提出的处理运行时权限的最干净的解决方案是在协程中运行一个无限循环,该协程贪婪地检查您需要的权限,如果不是,则提示用户授予每个权限
乍一看可能听起来很难看,但考虑到当请求权限时,循环被中断的原因与您的代码不起作用的原因相同:因为权限请求 UI 面板占据了前景,并且您的应用程序被暂停,当焦点时返回您的循环再次开始检查丢失的权限,另外您可以使用 yield return new WaitForSeconds(0.2f) 减慢循环
这是带有一些装饰的代码,用于通知用户如果不授予所需的所有权限就无法继续:
private bool _locationPermissionAsked;
private bool _microphonePermissionAsked;
private bool _cameraPermissionAsked;
private bool _storagePermissionAsked;
private void Start()
{
#if UNITY_ANDROID && !UNITY_EDITOR
StartCoroutine(RequestPermissionsRoutine());
#else
/***** Ready to run you app *****/
#endif
}
private IEnumerator RequestPermissionsRoutine()
{
yield return new WaitForEndOfFrame();
while (true)
{
// For each permission you need, build a block like the following, it could
// have been done dynamically but given the small number of possible options
// I preferred to keep it extended
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation) && !_locationPermissionAsked)
{
// This flag keeps track of the user choice against the permission panel
//
// if he choose to NOT grant the permission we skip the permission request
// because we are gonna notify him that he needs to grant the permission later
// using a message in our App
_locationPermissionAsked = true;
// You can even ask permissions using android literal definition instead of Unity's Permission.FineLocation
yield return Permission.RequestPermission("android.permission.ACCESS_FINE_LOCATION").WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone) && !_microphonePermissionAsked)
{
_microphonePermissionAsked = true;
yield return Permission.RequestPermission(Permission.Microphone).WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.Camera) && !_cameraPermissionAsked)
{
_cameraPermissionAsked = true;
yield return Permission.RequestPermission(Permission.Camera).WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite) && !_storagePermissionAsked)
{
_storagePermissionAsked = true;
yield return Permission.RequestPermission(Permission.ExternalStorageWrite);
continue;
}
// This is the part where we check if all the permissions were granted
// and allow the user to run the App ( else condition )
// or prompt him to grant the permissions he denied
//
// Note that this code is never reached before each permission have been asked
// once, because of the "continue;"s used before
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation) ||
!Permission.HasUserAuthorizedPermission(Permission.Microphone) ||
!Permission.HasUserAuthorizedPermission(Permission.Camera) ||
!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
{
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation))
{
/***** Tell the user to grant FineLocation Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
{
/***** Tell the user to grant Microphone Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
{
/***** Tell the user to grant Camera Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
{
/***** Tell the user to grant ExternalStorageWrite Permission *****/
}
/***** This is where all permissions have been asked once *****/
/***** and one or more were NOT granted, *****/
/***** you can write the code to handle this fallback here *****/
}
else
{
// I like to give some time to the Android looper before running my App, just to be safe
yield return new WaitForSeconds(1f);
/***** Ready to run you App *****/
}
// Slow down the loop by a little bit, not strictly needed but not harmful either
yield return new WaitForSeconds(0.2f);
}
}
即使在以下情况下也有效,例如,用户拒绝一个权限然后强行杀死您的应用程序,或者其他一些应用程序意外抢占前台以及我迄今为止遇到的各种其他风险案例
我要补充一点:如果您使用的是 Google ARCore,请注意它会覆盖原始 Unity 的权限请求机制 ( https://github.com/google-ar/arcore-unity-sdk/issues/151 ) 鼓励开发人员使用它自己的 GoogleARCore.AndroidPermissionsManager 而不是 UnityEngine.Android.Permission,因此 UnityEngine.Android.Permission 将不起作用,您仍然可以使用此脚本,但您需要将所有“Permission.RequestUserPermission”替换为“AndroidPermissionsManager” .RequestUserPermission”(您不需要替换“Permission.HasUserAuthorizedPermission”,它们仍然有效),甚至更好,我可以为您完成:
private IEnumerator RequestPermissionsRoutine()
{
yield return new WaitForEndOfFrame();
while (true)
{
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation) && !_locationPermissionAsked)
{
_locationPermissionAsked = true;
yield return AndroidPermissionsManager.RequestPermission("android.permission.ACCESS_FINE_LOCATION").WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone) && !_microphonePermissionAsked)
{
_microphonePermissionAsked = true;
yield return AndroidPermissionsManager.RequestPermission(Permission.Microphone).WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.Camera) && !_cameraPermissionAsked)
{
_cameraPermissionAsked = true;
yield return AndroidPermissionsManager.RequestPermission(Permission.Camera).WaitForCompletion();
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite) && !_storagePermissionAsked)
{
_storagePermissionAsked = true;
yield return AndroidPermissionsManager.RequestPermission(Permission.ExternalStorageWrite);
continue;
}
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation) ||
!Permission.HasUserAuthorizedPermission(Permission.Microphone) ||
!Permission.HasUserAuthorizedPermission(Permission.Camera) ||
!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
{
if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation))
{
/***** Tell the user to grant FineLocation Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
{
/***** Tell the user to grant Microphone Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
{
/***** Tell the user to grant Camera Permission *****/
}
if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
{
/***** Tell the user to grant ExternalStorageWrite Permission *****/
}
/***** This is where all permissions have been asked once *****/
/***** and one or more were NOT granted, *****/
/***** you can write the code to handle this fallback here *****/
}
else
{
yield return new WaitForSeconds(1f);
/***** Ready to run you App *****/
}
yield return new WaitForSeconds(0.2f);
}
}