Android M Runtime Permission Issue in Unity Game Development

关于有史以来遇见过的最麻烦的游戏bug: Android M Permission

问题描述:

Android M 允许玩家在游戏安装后,修改游戏访问设备的权限。当玩家禁止游戏访问设备摄像头之后,游戏中的AR scene 依旧可以照常运行并不显示任何提示信息。

具体权限访问改变参考此处:https://blog.xamarin.com/requesting-runtime-permissions-in-android-marshmallow/

经过调查,游戏AR scene 的错误监控系统来自 Vufornia 的自带错误监控系统。然而,糟糕的是,Vufoirnia 并没有兼容 Android 的最新版本。每次AR scene 初始化时,访问的 Init 信息为 success。 这意味着,我必须自创一种检测方式,来检测游戏是否有权限访问设备的摄像头。

最开始,我尝试了两种方法:WebCamTexture (http://docs.unity3d.com/ScriptReference/WebCamTexture.html) 和 CameraDevice( https://developer.vuforia.com/library/sites/default/api/unity/classVuforia_1_1CameraDevice.html)。

前者是 Unity 提供的 api,后者是 Vuforinia 提供的对象。我本以为,如果摄像头访问权限受限后,api 返回的 active device 数目应该为 0。但是,实际返回对象数目依旧是 2 (前置和后置摄像头)。其次,我试图通过摄像头的各种参数,来区分权限访问情况。但是,无论是检测 Camera 的 buffer 是否在上一帧有更新,或者是检查 Camera 的 field of view,即使 permission 被禁止了,这些信息依旧可以被访问。

于是,我不得不把方向转向 Android M 的常规解决办法。http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/ 和 https://developer.android.com/training/permissions/requesting.html

这里的关键 api 是 checkSelfPermission。要调用该 api,最直接的办法是,创建自己的 jar,并添加到项目中。之后再用 C# 代码调用。但是,还有一种更简单的办法,即用 Unity 提供的 api 直接调用 Android 函数。方法在此:http://docs.unity3d.com/ScriptReference/AndroidJavaClass.html

我们既可以通过 AndrpidJavaClass 调用 static 函数,可以通过 AndroidJavaObject 调用 non-static 函数。以下是我的测试代码:

  1.             AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
  2.             AndroidJavaObject activity = jc.GetStatic<AndroidJavaObject>(“currentActivity”);
  3.             AndroidJavaObject context = activity.Call<AndroidJavaObject>(“getApplicationContext”);
  4.             AndroidJavaObject ContextCompat = new AndroidJavaObject(“android.support.v4.content.ContextCompat”);
  5.             AndroidJavaClass ActivityCompatClass = new AndroidJavaClass(“android.support.v4.app.ActivityCompat”);
  6.             int hasCameraPermission = context.Call<int>(“checkSelfPermission”, “android.permission.CAMERA” );
  7.             ActivityCompatClass.CallStatic(“requestPermissions”, context, “android.permission.CAMERA”, 1000 );
  8.             //int hasCameraPermission = ContextCompat.Call<int>(“checkSelfPermission”, context, “android.permission.CAMERA” );

但是糟糕的是,如果我用 ContextCompat.checkSelfPermission 调用 static 函数,程序将会报错显示无法找到该 static 函数。如果我使用 context.checkSelfPermission 调用 non-static 函数,虽然 method 会被调用,但是返回的值永远都是 0 (granted)。

后来经过再三检查,发现其问题在于我们使用的 library 不是最新版本,无法支持 Android api 23 及以上的版本。如果更新 lib 的话,会花费相当多的时间去清理和调整。

最后,我们尝试更改 Manifest 中的 targetVersion 来禁止用户修改游戏的访问权限。但是,这种方法也失败了。原因在于 targetVersion 的具体意思是指告知设备该程序已经在通过 targetVersion 的目标版本测试。然而我们的游戏实际并不满足目标版本,但是设备依然会按照应有的方式处理我们的程序。详细见此:

http://www.cnblogs.com/popapa/p/android_uses-sdk-element.html
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html

最后是网上另外两名用户的解决办法: http://blog.trsquarelab.com/2015/11/  和 http://stackoverflow.com/questions/35027043/implementing-android-6-0-permissions-in-unity3d/