以我为例,我使用了单位的 OnApplicationFocus 回调函数。当权限窗口打开时,应用程序将失去其焦点模式;当权限窗口关闭(用户接受或拒绝权限)时,应用程序将再次获得其焦点模式。每次 OnApplicationFocus 回调调用。
它似乎很脏,但效果很好。您还必须在清单文件中添加权限。
Please see this GitHub link for see the full project
public class AndroidPermissionHandler : MonoBehaviour
{
bool isItPermissionTime = false;
string nextPermission;
Stack<string> permissions = new Stack<string>();
void Start()
{
OpenAllPermissions();
}
public void OpenAllPermissions()
{
isItPermissionTime = true;
CreatePermissionList();
}
void CreatePermissionList()
{
permissions = new Stack<string>();
permissions.Push(Permission.ExternalStorageWrite);
permissions.Push(Permission.Camera);
permissions.Push(Permission.CoarseLocation);
AskForPermissions();
}
void AskForPermissions ()
{
if (permissions == null || permissions.Count <= 0)
{
isItPermissionTime = false;
return;
}
nextPermission = permissions.Pop();
if (nextPermission == null)
{
isItPermissionTime = false;
return;
}
if (Permission.HasUserAuthorizedPermission(nextPermission) == false)
{
Permission.RequestUserPermission(nextPermission);
}
else
{
if (isItPermissionTime == true)
AskForPermissions();
}
Debug.Log("Unity>> permission " + nextPermission + " status ;" + Permission.HasUserAuthorizedPermission(nextPermission));
}
private void OnApplicationFocus(bool focus)
{
Debug.Log("Unity>> focus .... " + focus + " isPermissionTime : " + isItPermissionTime);
if (focus == true && isItPermissionTime == true)
{
AskForPermissions();
}
}
,
Permission.RequestUserPermission
似乎以某种方式异步工作,并且在已经显示对话框的情况下不会显示对话框-因此,在找到第一个未经授权的权限之后,只需跳过所有其他权限。
我可以绕过这样的问题:
private IEnumerator AskForPermissions()
{
#if UNITY_ANDROID
List<bool> permissions = new List<bool>() { false,false,false };
List<bool> permissionsAsked = new List<bool>() { false,false };
List<Action> actions = new List<Action>()
{
new Action(() => {
permissions[0] = Permission.HasUserAuthorizedPermission(Permission.Microphone);
if (!permissions[0] && !permissionsAsked[0])
{
Permission.RequestUserPermission(Permission.Microphone);
permissionsAsked[0] = true;
return;
}
}),new Action(() => {
permissions[1] = Permission.HasUserAuthorizedPermission(Permission.Camera);
if (!permissions[1] && !permissionsAsked[1])
{
Permission.RequestUserPermission(Permission.Camera);
permissionsAsked[1] = true;
return;
}
}),new Action(() => {
permissions[2] = Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite);
if (!permissions[2] && !permissionsAsked[2])
{
Permission.RequestUserPermission(Permission.ExternalStorageWrite);
permissionsAsked[2] = true;
return;
}
}),new Action(() => {
permissions[3] = ermission.HasUserAuthorizedPermission("android.permission.READ_PHONE_STATE");
if (!permissions[3] && !permissionsAsked[3])
{
Permission.RequestUserPermission("android.permission.READ_PHONE_STATE");
permissionsAsked[3] = true;
return;
}
})
};
for(int i = 0; i < permissionsAsked.Count; )
{
actions[i].Invoke();
if(permissions[i])
{
++i;
}
yield return new WaitForEndOfFrame();
}
#endif
}
,
众所周知,Android运行时权限很麻烦,在您的情况下,问题是Android的权限请求UI面板在您的第一个Permission.RequestUserPermission上占据了前台,这会挂起您的App并阻止执行以下代码
到目前为止,我提出的用于处理运行时权限的最干净的解决方案是在协程中运行无限循环,该协程贪婪地检查所需的权限,并提示用户授予每个权限(如果不是)
乍一看听起来很丑陋,但请考虑一下,当您请求权限时,由于代码无法正常工作的相同原因而中断了循环:由于权限请求UI面板占据了前台,并且您的应用程序被暂停,当焦点被放回时,您的循环将再次开始以检查缺少的权限,此外,您还可以使用yield return新的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 ammount 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);
}
}
,
我正在从事的项目遇到相同的问题。
一个简单的解决方法是在每个权限之间使用协程请求权限,并在其中等待几秒钟的收益回报。或者只是在应用程序的不同位置请求权限。例如,仅在用户将要使用它时才请求相机许可,或者在用户将要访问它时只写外部存储器。由于这些是敏感权限,因此最好让用户知道为什么要求他事先授予这些权限的原因。
IEnumerator Start() {
// Ask for camera permission
if(!Permission.HasUserAuthorizedPermission(Permission.Camera)) {
Permission.RequestUserPermission(Permission.Camera);
}
yield return new WaitForSeconds(2.5f);
// Ask for external storage permission
if(!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite)) {
Permission.RequestUserPermission(Permission.ExternalStorageWrite);
}
}
上面的代码正在工作。您可以调整“等待秒数”值,并添加所需的权限。请注意,只有在尚未授予权限的情况下,我才会请求权限。
干杯!
本文链接:https://www.f2er.com/3152864.html