Unity Android动态请求权限

Posted 长江很多号

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity Android动态请求权限相关的知识,希望对你有一定的参考价值。

码字不易,转载请注明出处:
https://blog.csdn.net/newchenxf/article/details/119956445


前言

android 6(API 级别 23)及更高版本上,Android.Permission API 要求在需要时,动态请求使用某些常用系统功能(例如相机、麦克风或位置)的权限,而不是在应用程序启动时立即请求权限。

Unity的Android版本,一样要遵守这个要求。

这里介绍2种方法,一种是C#直接请求,一种是C#调用Android的java代码请求。

1. Unity的C#直接请求

Unity本身有动态权限的请求方法。但是这种比较局限,比如,无法获得权限请求的结果。anyway,这里还是介绍一下:
以/sdcard权限读取为例子:

using UnityEngine;
# if PLATFORM_ANDROID
using UnityEngine.Android;
# endif

public class PermissionTest : MonoBehaviour 
{
    GameObject dialog = null;
    
    void Start ()
    {
        #if PLATFORM_ANDROID
        if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead))
        {
            Permission.RequestUserPermission(Permission.ExternalStorageRead);
            dialog = new GameObject();
            }
        #endif
    }

    void OnGUI ()
    {
        #if PLATFORM_ANDROID
        if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead))
        {
            // 用户拒绝了使用的权限。
            //显示一条包含 Yes/No 按钮的消息,说明需要该权限的原因。
            //如果用户选择 yes,则再次提出请求
            // 在此处显示对话框。
            dialog.AddComponent<PermissionsRationaleDialog>();
            return;
        }
        else if (dialog != null)
        {
            Destroy(dialog);
        }
        #endif

        //现在可以用麦克风执行所需的操作了
    }
}

Dialog的代码。

using UnityEngine;
# if PLATFORM_ANDROID
using UnityEngine.Android;
# endif

public class PermissionsRationaleDialog : MonoBehaviour
{
    const int kDialogWidth = 300;
    const int kDialogHeight = 100;
    private bool windowOpen = true;

    void DoMyWindow(int windowID)
    {
        GUI.Label(new Rect(10, 20, kDialogWidth - 20, kDialogHeight - 50), "Please let me use the storage.");
        GUI.Button(new Rect(10, kDialogHeight - 30, 100, 20),"No");
        if (GUI.Button(new Rect(kDialogWidth - 110, kDialogHeight - 30, 100, 20), "Yes"))
        {
            #if PLATFORM_ANDROID
            Permission.RequestUserPermission(Permission.Microphone);
            #endif
            windowOpen = false;
        }
    }

    void OnGUI ()
    {
        if (windowOpen)
        {
            Rect rect = new Rect((Screen.width / 2) - (kDialogWidth / 2), (Screen.height / 2) - (kDialogHeight / 2), kDialogWidth, kDialogHeight);
            GUI.ModalWindow(0, rect, DoMyWindow, "Permissions Request Dialog");
        }
    }
}

应将 PermissionTest(而不是 PermissionsRationaleDialog)作为组件添加到游戏对象。PermissionTest会自动创建一个游戏对象,并在需要显示对话框时添加 PermissionsRationaleDialog。

2. Unity C#调用Android请求权限

2.1 Unity代码

AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

//Android完成权限请求后的回调函数
public void onPermissionResult(String resultCode)
    {
        Debug.Log(TAG + "onPermissionResult resultCode " + resultCode);
        if ("1".Equals(resultCode))
        {
            Invoke("preparePlay", 2);
        }
        else
        {
            Debug.Log(TAG + "not permission to read local file");
        }
    }

    private void checkPermission()
    {
        Debug.Log(TAG + "checkPermission");
        AndroidJavaObject nativeObject = new AndroidJavaObject("com.iqiyi.cutgreenvideosdk.PermissionHelper");
        nativeObject.CallStatic("checkPermission", activity, "AndroidVideoScreen", "onPermissionResult");//AndroiwdVideoScreen 为脚本挂载的对象,onPermissionResult为脚本监听回调的函数名称 
    }

2.2 Android 端的代码

Android端需要拿到activity的实例,才可以发起请求,注意,application context是不可以的喔!

因为Android端没有activity的代码,所以也无法监听权限的回调。所以只能加一个handler轮询,得到权限后,通过消息告诉Untiy。

以下是具体代码:

package com.iqiyi.cutgreenvideosdk;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.unity3d.player.UnityPlayer;

import java.lang.ref.WeakReference;

public class PermissionHelper {
    private static final String TAG = "PermissionHelper";
    private MyHandler myHandler;
    private Context mContext;
    private static int checkCount = 0;
    private static String mGameObject = "";
    private static String mCallbackFunction = "";

    private static class SingletonHolder {
        private static final PermissionHelper INSTANCE = new PermissionHelper();
    }

    private PermissionHelper() {
        myHandler = new MyHandler(this);
    }

    public static final PermissionHelper getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 请求权限
     *
     * @param context          必须为activity,否则framework会报错IllegalArgumentException: android.app.Application is not supported
     * @param gameObject
     * @param callbackFunction
     */
    public static void checkPermission(Context context, String gameObject, String callbackFunction) {
        Log.i(TAG, "checkPermission gameObject " + gameObject + " callbackFunction " + callbackFunction);
        mGameObject = gameObject;
        mCallbackFunction = callbackFunction;
        if (context == null)
            return;

        getInstance().mContext = context;
        boolean hasPermission = PermissionUtils.checkPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
        if (hasPermission) {
            Log.w(TAG, "checkPermission, has permission");
            notifyResult(true);
        } else {
            showPermissionDialog(context);
        }
    }

    private static void notifyResult(boolean permissionGranted) {
        try {
            //参数1, 脚本挂载的gameObject名称,参数2, 脚本方法,参数3,返回值
            Log.w(TAG, "notifyResult, permissionGranted " + permissionGranted + " mGameObject " + mGameObject + " mCallbackFunction " + mCallbackFunction);
            UnityPlayer.UnitySendMessage(mGameObject, mCallbackFunction, permissionGranted ? "1" : "0");
            getInstance().mContext = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void showPermissionDialog(final Context context) {
        Log.w(TAG, "showPermissionDialog");
        if (context == null)
            return;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage("我们需要读存储权限来播放本地视频,您是否允许?");
        builder.setCancelable(true);

        builder.setPositiveButton(
                "允许",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.cancel();
                        reqPermission(context);
                    }
                });

        builder.setNegativeButton(
                "取消",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.cancel();
                    }
                });

        AlertDialog alertDialog = builder.create();
        alertDialog.show();

        getInstance().myHandler.sendEmptyMessageDelayed(MyHandler.CHECK_PERMISSION, 2000);
    }


    private static void reqPermission(Context context) {
        if (context instanceof Activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                ((Activity) context).requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PermissionUtils.REQ_CODE);
            }
        }
    }

    private static void checkPermission() {
        checkCount++;
        if (checkCount > 20) {
            notifyResult(false);
            return;
        }

        if (getInstance().mContext != null && PermissionUtils.checkPermission(getInstance().mContext, Manifest.permission.READ_EXTERNAL_STORAGE)) {
            Log.w(TAG, "got permission");
            notifyResult(true);
        } else {
            Log.w(TAG, "keep checkPermission");
            getInstance().myHandler.sendEmptyMessageDelayed(MyHandler.CHECK_PERMISSION, 2000);
        }
    }

    private static class MyHandler extends Handler {
        private final WeakReference<PermissionHelper> mRefs;
        public static final int CHECK_PERMISSION = 1;

        public MyHandler(PermissionHelper instance) {
            super(Looper.getMainLooper());
            mRefs = new WeakReference<>(instance);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mRefs.get() == null) {
                return;
            }

            switch (msg.what) {
                case CHECK_PERMISSION:
                    mRefs.get().checkPermission();
                    break;
                default:
                    break;
            }
        }
    }
}

有关Android的模块如何在Unity中使用,可以参考这篇文章:
https://blog.csdn.net/newchenxf/article/details/119934004

以上是关于Unity Android动态请求权限的主要内容,如果未能解决你的问题,请参考以下文章

100个 Unity踩坑小知识点| Unity调用API ,动态获取Android权限,附带所有Android权限表格

Unity 安卓权限、动态安卓权限

在android中动态创建选项卡并使用传入的参数加载片段

Unity - Android - BLE 蓝牙权限

Unity在Android 6.0及以上版本弹出权限申请窗口的问题

Android 6.0以上动态请求权限的工具类