请使用最新文章:

Unity2022中的android权限处理(Permissions)
动态权限,权限弹窗

注意事项:
1.因为新规等因素需要提前弹出游戏自己的权限描述界面
2.玩家连续多次拒绝权限的处理

下面的文章可以参考android的实现原理,代码已过时

目录

0.unity2020 最正确的权限处理打开方式

第一步 unity activity中设置屏蔽android权限弹窗,避免一点开应用各种权限无序弹出

第二步 在C#中指定调用接口,方便控制各个功能的权限弹出

第三步 对于实在搞不明白Android权限申请处理和弹窗的,提供个三方类库,直接引用使用(easypermissions)

1.unity2019中已经提供了面向Android的 权限申请方法

2.疑难问题以及如何解决

.权限不弹提示窗

.自定义弹窗不展示

3.原理解析以及在Android中的使用(建议使用):

.监听权限处理结果

.动态检查权限

.请求权限

.ex.简单示例 (截图保存到相册并刷新,动态申请权限)

.unity 内直接调用Android方法

4.ex:unity+android权限--打开应用不弹权限,动态请求权限 完整例子展示





0.unity2020 最正确的权限处理打开方式

第一步 unity activity中设置屏蔽android权限弹窗,避免一点开应用各种权限无序弹出

<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
    <application
        android:name="com.longtu.android.channels.Info.LTBase_Channels_Application"
        android:allowBackup="true"
		android:usesCleartextTraffic="true"
		
		android:label="@string/app_name">
        <activity android:name="com.longtugame.rjsdk.MainActivity"
                android:configChanges="orientation|keyboard|keyboardHidden|screenLayout|screenSize"
                android:allowEmbedded="@string/app_name"
				android:exported = "true"
                android:theme="@android:style/Theme.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity"
                        android:value="true" />
			<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
        </activity>

第二步 在C#中指定调用接口,方便控制各个功能的权限弹出

    /// <summary>
    /// 极光初始化(初始化接口,请求必须权限,打开极光推送日志)
    /// </summary>
    public static void LT_JPushInit()
    {
        s_LTSDKImpl.LT_RequestPermissions();
        s_LTSDKImpl.LT_SetDebugMode(true);
        s_LTSDKImpl.LT_JPushInit();
    }

第三步 对于实在搞不明白Android权限申请处理和弹窗的,提供个三方类库,直接引用使用(easypermissions)

具体可百度easypermissions框架使用,

也可参考:

Android调用相册、相机(兼容6.0、7.0、8.0)_P_Frank的博客-CSDN博客_android打开相册


    //动态权限申请库
    implementation 'pub.devrel:easypermissions:1.3.0'

1.unity2019中已经提供了面向Android的 权限申请方法

其实调用的是Android内的方法,不过还是建议使用Android原生方法进行判断,可以监听权限申请结果和判断。

ex:UnityEngine.Android.Permission.RequestUserPermission(s);

重要提示:使用unity的动态权限申请可以动态的弹出是否同意该权限界面,方便了很多


    string[] strs=new string[] {
        "android.permission.INTERNET",
        "android.permission.READ_PHONE_STATE",
        "android.permission.READ_EXTERNAL_STORAGE",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "android.permission.ACCESS_WIFI_STATE",
        "android.permission.ACCESS_NETWORK_STATE",
        "android.permission.GET_TASKS",
        "android.permission.REQUEST_INSTALL_PACKAGES",
        "android.permission.WAKE_LOCK",
        "android.permission.SYSTEM_ALERT_WINDOW",
        "android.permission.CHANGE_WIFI_STATE",
        "android.permission.CHANGE_NETWORK_STATE",
        "android.permission.ACCESS_COARSE_LOCATION",
        "android.permission.ACCESS_FINE_LOCATION",
        "android.permission.SYSTEM_OVERLAY_WINDOW",
        "android.permission.ACCESS_COARSE_UPDATES",
        "android.permission.WRITE_SETTINGS",
        "android.permission.BATTERY_STATS",
        "android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
    }; 

    // Use this for initialization
    void Start () {
        Debug.Log("start main");
        // var iscon= PlayerConnection.instance.isConnected;

        strs.ToList().ForEach(s=>{
            //Debug.Log("RequestUserPermission: "+s);
            //if (!Permission.HasUserAuthorizedPermission(s))
            //{
                Permission.RequestUserPermission(s);
          
                Debug.Log("add RequestUserPermission: " + s);
            //}
            //else
            //{
            //    Debug.Log("it has RequestUserPermission: " + s);
            //}
        });
      


         //UnityEngine.Networking.PlayerConnection.PlayerConnection.
         //实例化上下文环境
        // adUnionContext = AdUnionContext.GetInstance();
        初始化SDK
        //AdUnionSDK.Init(APP_ID, new OnAuInitListenerProxy()); 

        初始化unity自带的控件
        initComponents();

    } 

2.疑难问题以及如何解决

.权限不弹提示窗

android 中的权限只有部分危险权限会弹窗,结合相关功能,查找某条弹窗权限如文件写入,相机使用等,需要和弹窗一 一对应,没有提示的权限建议不要动态申请,或者不做权限检测

中间遇到的问题,配置在AndroidManifest.xml中的权限有时候会导致不能动态申请到所需权限,所以可以全部注释掉,然后动态添加。

系统权限分为两类:正常权限和危险权限。

  • 正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
  • 危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。

权限是分组的,同一组的权限申请其中一个,同组的权限就全部都申请了。

特殊权限组:  

  • CALENDAR 日历
  • CAMERA 相机
  • CONTACTS 联系人
  • LOCATION 定位
  • MICROPHONE 麦克相关,比如录音  
  • PHONE 手机状态  
  • SENSORS 传感器  
  • SMS 短信  
  • STORAGE 存储权限


.自定义弹窗不展示

有时候权限申请需要自己写弹窗,需要在主线程和UI线程调用,可以参考上面的例子。

3.原理解析以及在Android中的使用(建议使用):

其实调用的是Android内的方法

.监听权限处理结果

	@Override
	public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)
	{
		LTBaseSDK.getInstance (this).onRequestPermissionsResult (requestCode, permissions, grantResults);
		super.onRequestPermissionsResult (requestCode, permissions, grantResults);

		if (requestCode ==250 || requestCode==251)
		{
			//特殊处理截图权限
			LTSDK.LT_AutoPermissionChecker(requestCode, permissions, grantResults);
		}
		
	}

.动态检查权限

	// 动态检查权限
	public static void LT_AutoPermissionChecker ( int requestCode, String[] permissions, int[] grantResults)
	{
		Log.i ("LTSDK_Java", "LT_AutoPermissionChecker requestCode:"+requestCode);
		
		String pName="";
		if (requestCode ==250 )
		{
			pName="android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
		}
		else if(requestCode==251)
		{
			pName="android.permission.WRITE_EXTERNAL_STORAGE";
		}
		

		LT_RequirePermission (pName,requestCode);					
	}

.请求权限

	public static void LT_RequirePermission (final String pName,final int requestCode)
	{
		Log.i ("LTSDK_Java", "LT_RequirePermission pName:"+pName+requestCode);
		if (ContextCompat.checkSelfPermission(UnityPlayer.currentActivity, pName) !=  PackageManager.PERMISSION_GRANTED)
		{
			Log.i ("LTSDK_Java", "checkSelfPermission pName: false:"+pName);
//		   if (ActivityCompat.shouldShowRequestPermissionRationale(UnityPlayer.currentActivity, pName))
//		   {
			((MainActivity)UnityPlayer.currentActivity).runOnUiThread(new Runnable() {
				
				public void run() {
					
					   final String perName=pName;
					   AlertDialog.Builder builder=new AlertDialog.Builder(UnityPlayer.currentActivity);
					   builder.setTitle("提示:")
					   .setMessage("需要权限:"+requestCode)
					   .setPositiveButton("OK", new OnClickListener() { 
						   
						   public void onClick(DialogInterface var1, int var2) {
							   Log.i ("LTSDK_Java", "requestPermissions pName: :"+perName);
							   ActivityCompat.requestPermissions(UnityPlayer.currentActivity,new String[] {perName}, requestCode); 
						   }
						   
					   })
					   .setNegativeButton("Cancel", new OnClickListener() { 
					   
						   	public void onClick(DialogInterface var1, int var2) {
							   
						   }
					   });
					   builder.create().show();
				}
			}); 
			
//		   }
		}
	}

.ex.简单示例 (截图保存到相册并刷新,动态申请权限)

	public static void LT_SavePhoto (String photoPath,String tarPath)
	{
		
//		if (ContextCompat.checkSelfPermission(UnityPlayer.currentActivity,android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) !=  PackageManager.PERMISSION_GRANTED )
//		{
//			LTSDK.LT_RequirePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,250);
//			Log.i ("LTSDK_Java", "LT_SavePhoto LT_RequirePermission:"+250);
//		}
		if(ContextCompat.checkSelfPermission(UnityPlayer.currentActivity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) !=  PackageManager.PERMISSION_GRANTED)
		{
			LTSDK.LT_RequirePermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,251);
			Log.i ("LTSDK_Java", "LT_SavePhoto LT_RequirePermission:"+251);
		}
		else
		{
			//copy to picture 
			copyFile(photoPath,tarPath);
			 Log.i ("LTSDK_Java", "LT_SavePhoto copyFile");
		    //refpic
		    String[] paths = {photoPath,tarPath};
		    String[] mimeTypes = {"image/jpeg", "image/png"};
		    MediaScannerConnection.scanFile(UnityPlayer.currentActivity, paths, mimeTypes,
		            new MediaScannerConnection.OnScanCompletedListener() {
		                @Override
		                public void onScanCompleted(String path, Uri uri) {
		                	 Log.i ("LTSDK_Java", "photoPath suck");
		                }
		            });
		   
		}
		
	}

.unity 内直接调用Android方法

   
  #if UNITY_ANDROID
        private AndroidJavaClass _request;
        public  AndroidJavaClass Request {
            get {
                if (_request == null)
                    _request = new AndroidJavaClass ("com.example.androidpermissionmgr.PermissionProvider");
                return _request;
            }
        }
        #else

 public void RequestPermissions (int requestCode, params string[]permissions)
        {
            Debug.Log ("[PermissionProvider] Requesting permissions: "+ requestCode + " " + permissions );
            //Request.CallStatic ("verifyPermissions", gameObject.name, requestCode, permissions);
            //requestPermissions
Request.CallStatic ("verifyPermissions");
        }

java 内申请权限

import android.support.v4.content.PermissionChecker;
import android.support.v4.app.ActivityCompat;
//前面说过了静态方法,android.permission.WRITE_EXTERNAL_STORAGE是外部存储权限,同理其他权限也可以动态请求
public static void verifyPermissions() {
     //检查权限避免重复请求相同权限,参数:activity,权限名
        if (PermissionChecker.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != 0) {
            ActivityCompat.requestPermissions(this, new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, 100);//请求权限,参数:activity,权限名,请求码(不同的权限要求不同的请求码,可以自己定,比如我这个权限是100,另外的可以填102,103...)
        }
}

4.ex:unity+android权限--打开应用不弹权限,动态请求权限 完整例子展示

首先,屏蔽权限弹窗,AndroidManifest.xml里面加入

<!-- Unity打包屏蔽android权限弹窗-->
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
接下来是请求权限,在你需要的位置请求

//unity api 请求
Permission.RequestUserPermission(s);

//java 请求
        if (PermissionChecker.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != 0) {
            ActivityCompat.requestPermissions(this, new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, 100);//请求权限,参数:activity,权限名,请求码(不同的权限要求不同的请求码,可以自己定,比如我这个权限是100,另外的可以填102,103...)
        }



//java层 监听结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
   super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  if(100 != requestCode)return;//我们刚才定义的请求码是100,名称也可以判断
  //给个弹窗告知玩家这个权限不会对他造成影响  
  if (ActivityCompat.shouldShowRequestPermissionRationale("只会写入游戏安装目录,不会影响系统安全", "android.permission.WRITE_EXTERNAL_STORAGE")) {
      (new Builder(this)).setMessage(string.storage_permissions_remind)
      .setPositiveButton("OK", new OnClickListener() {
           public void onClick(DialogInterface var1, int var2) {
          //点击ok,则再次请求
          requestExternalStorage();
           }
      }).setNegativeButton("Cancel", new OnClickListener() {
          public void onClick(DialogInterface var1, int var2) {
              //点击cancel,todo
          }
      }).create().show();
  super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐