Unity 权限 之 Android 【权限 动态申请】功能的简单封装

Unity 权限 之 Android 【权限 动态申请】功能的简单封装

目录

Unity 权限 之 Android 【权限 动态申请】功能的简单封装

一、简单介绍

二、Android 权限 动态申请

三、实现原理

四、注意事项

五、案例实现简单步骤

附录:

一、进一步优化

二、多个权限申请代码参考


一、简单介绍

Unity 是一个功能强大的跨平台游戏引擎,广泛用于开发视频游戏和其他实时3D互动内容,如模拟器和虚拟现实应用。

  1. 游戏引擎

    • Unity:Unity Technologies 开发的跨平台游戏引擎,支持2D和3D图形、物理引擎、音频、视频、网络和多平台发布。
    • 跨平台支持:Unity 支持在多个平台上发布,包括 Windows、macOS、Linux、iOS、Android、WebGL、PlayStation、Xbox、Switch 等。
  2. 开发环境

    • Unity Editor:用于创建和管理 Unity 项目的集成开发环境(IDE)。开发者可以在其中创建场景、设计关卡、编写代码和调试游戏。
    • 场景(Scene):Unity 中的基本构建块,一个场景可以被视为一个关卡或一个游戏中的独立部分。
  3. 编程语言

    • C#:主要编程语言。Unity 使用 C# 脚本来控制游戏对象和实现游戏逻辑。
    • UnityScript(已弃用):曾经支持的 JavaScript 变种,但已经被弃用。

Unity 进阶开发涉及更复杂的技术和更深入的知识,以创建高性能、复杂和专业的游戏和应用程序。以下是一些 Unity 进阶开发的关键领域和技术:

  • 设计模式

    • 学习和应用常见的设计模式(如单例模式、工厂模式、观察者模式)以便更好地组织和管理代码。
  • 异步编程

    • 使用 C# 的 asyncawait 关键字进行异步编程,以提高应用的响应速度和性能。
  • 依赖注入

    • 使用依赖注入(如 Zenject)来管理对象的依赖关系,减少耦合,提高代码的可测试性和可维护性。

二、Android 权限 动态申请

在开发 Unity Android 应用时,动态获取权限是一个常见的需求。由于 Android 6.0(API 级别 23)引入了运行时权限模型,应用必须在运行时请求某些权限。下面是一个如何在 Unity 中封装动态获取权限功能的示例。

在 Unity 中,仅使用 C# 代码来处理 Android 动态权限请求是可能的,但仍需要调用 Android 的原生 API。这可以通过 AndroidJavaClassAndroidJavaObject 来实现。

三、实现原理

PermissionManager 是一个用于管理 Android 权限请求的单例类。其主要功能是动态请求权限并在用户响应后处理结果。以下是其工作原理和实现步骤的详细解释:

  1. 单例模式

    • PermissionManager 使用单例模式确保在整个应用生命周期中只有一个实例。
  2. 权限请求接口

    • RequestPermission 方法用于请求特定的权限。
    • 首先检查权限是否已经授予,如果已授予则立即调用回调函数返回结果。
    • 如果权限未授予,启动协程 RequestAndCheckPermission 请求权限并等待用户响应。
  3. 协程处理

    • RequestAndCheckPermission 方法通过协程 IEnumerator 实现异步等待。
    • 使用 Permission.RequestUserPermission 方法请求权限。
    • 使用 yield return new WaitForSeconds(1.0f) 等待一段时间,让用户有足够时间响应权限请求。
    • 等待结束后,再次检查权限状态并调用回调函数返回结果。

四、注意事项

  1. 权限列表

    • 确保在 AndroidManifest.xml 中声明所有需要请求的权限,否则请求可能会失败。
    • 例如:
      <uses-permission android:name="android.permission.CAMERA" />
  2. 权限请求的异步性

    • 用户响应权限请求的时间是不确定的。使用协程 (IEnumerator) 异步等待用户响应而不阻塞主线程是必要的。
    • yield return new WaitForSeconds(1.0f) 是一个简单的等待机制,实际项目中可能需要更复杂的逻辑来处理用户的响应。
  3. 回调函数

    • 确保传递给 RequestPermission 的回调函数能正确处理权限被授予或拒绝的情况。
    • 回调函数签名为 System.Action<string, bool>,其中第一个参数是权限名,第二个参数是权限是否被授予的布尔值。
  4. 用户体验

    • 提示用户为什么需要请求特定权限,以提高用户接受权限请求的概率。
    • 在权限被拒绝后,提供适当的反馈和处理机制,如再次请求权限或退出相关功能。
  5. 多权限请求

    • 当前示例处理单个权限请求。如果需要请求多个权限,可以扩展 PermissionManager 类以支持批量请求,并分别处理每个权限的授予结果。

五、案例实现简单步骤

1、新建一个 Unity 工程

2、新建脚本 PermissionWrapper 封装权限申请功能

3、新建脚本 TestPermissionWrapper 测试封装权限申请功能,申请 camera 权限

4、把 TestPermissionWrapper  挂载到场景中

5、在 Player Settings 中的 Build 中勾选 Custom Main Manifest ,添加 Camera 权限申请

6、打包运行

六、关键代码

1、PermissionWrapper


using UnityEngine;
using UnityEngine.Android;public class PermissionWrapper : MonoSingleton<PermissionWrapper>
{/// <summary>/// 请求权限/// </summary>/// <param name="permission">权限名称</param>/// <param name="callback">权限回调:true 权限获取成功回调,false 权限获取失败回调</param>public void RequestPermission(string permission, System.Action<string, bool> callback){if (Permission.HasUserAuthorizedPermission(permission)){callback?.Invoke(permission, true);}else{StartCoroutine(RequestAndCheckPermission(permission, callback));}}/// <summary>/// 协程请求权限/// </summary>/// <param name="permission">权限名称</param>/// <param name="callback">权限回调:true 权限获取成功回调,false 权限获取失败回调</param>/// <returns></returns>private System.Collections.IEnumerator RequestAndCheckPermission(string permission, System.Action<string, bool> callback){Permission.RequestUserPermission(permission);yield return new WaitForSeconds(1.0f);bool granted = Permission.HasUserAuthorizedPermission(permission);callback?.Invoke(permission, granted);}
}

2、TestPermissionWrapper


using UnityEngine;
using UnityEngine.Android;public class TestPermissionWrapper : MonoBehaviour
{private void Start(){// 请求摄像头权限PermissionWrapper.Instance.RequestPermission(Permission.Camera, OnPermissionResult);}private void OnPermissionResult(string permission, bool granted){if (granted){Debug.Log("权限已授予: " + permission);// 执行需要权限的功能}else{Debug.Log("权限被拒绝: " + permission);// 处理权限被拒绝的情况}}
}

3、MonoSingleton

using System;
using UnityEngine;public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{private static T m_Instance;public static T Instance{get{if ((UnityEngine.Object)m_Instance == (UnityEngine.Object)null){T[] array = UnityEngine.Object.FindObjectsOfType<T>();if (array != null && array.Length != 0){if (array.Length != 1){throw new Exception($"## Uni Exception ## Cls:{typeof(T)} Info:Singleton not allows more than one instance");}m_Instance = array[0];}else{m_Instance = new GameObject($"{typeof(T).ToString()}(Singleton)").AddComponent<T>();m_Instance.OnSingletonInit();}}return m_Instance;}}protected virtual void Awake(){m_Instance = this as T;}protected virtual void OnDestroy(){m_Instance = null;}protected virtual void OnSingletonInit(){}
}

4、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.unity3d.player"xmlns:tools="http://schemas.android.com/tools"><!--相机权限--><uses-permission android:name="android.permission.CAMERA" /><application><activity android:name="com.unity3d.player.UnityPlayerActivity"android:theme="@style/UnityThemeSelector"><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" /></activity></application>
</manifest>

附录:

一、进一步优化

  • 用户提示:在请求权限前,先提示用户为何需要该权限,增强用户接受度。
  • 多权限支持:实现多权限同时请求的逻辑。
  • 超时处理:考虑在等待用户响应时添加超时处理逻辑,避免无限期等待。
  • 权限变更监听:实现权限变更监听,当用户在应用设置中更改权限时做出相应处理。

通过这些改进和注意事项,可以确保权限请求功能更加健壮和用户友好。

二、多个权限申请代码参考

1、PermissionJudgeMgr

using FfalconXR;
using FFALFramework.UIModule;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Android;public class PermissionJudgeMgr : MonoSingleton<PermissionJudgeMgr>
{#region Data/// <summary>/// TAG/// </summary>const string TAG = "[PermissionJudgeMgr] ";/// <summary>/// 权限申请列表/// </summary>List<IRequestPermissionItem> m_RequestPermissionItemLst;/// <summary>/// 请求权限回调/// </summary>private PermissionCallbacks m_PermissionCallbacks;/// <summary>/// 全部权限允许后的事件/// </summary>public Action OnAllPermissionGrantedAction;/// <summary>/// 判断是否有权限/// </summary>public bool IsHasPermission { get { return JudgeIsHasPermission(); } }#endregion#region public function/// <summary>/// 检测 权限/// </summary>public void CheckAppPermission(){CheckRequestPermissionLst();}#endregion#region 生命周期/// <summary>/// OnSingletonInit/// </summary>protected override void OnSingletonInit(){base.OnSingletonInit();RegisterPermissionListener();}/// <summary>/// OnDestroy/// </summary>protected override void OnDestroy(){base.OnDestroy();UnRegisterPermissionListener();}#endregion#region private function/// <summary>/// 检测权限队列/// </summary>private void CheckRequestPermissionLst() {IRequestPermissionItem requestPermissionItem = null;foreach (var item in m_RequestPermissionItemLst){if (item.IsHasPermission == false){requestPermissionItem = item;break;}}if (requestPermissionItem != null){requestPermissionItem.RequestPermission(m_PermissionCallbacks);}else{OnAllPermissionGrantedAction?.Invoke();}}/// <summary>/// 注册权限监听/// </summary>private void RegisterPermissionListener(){UIManager.Instance.QuitAll();AddRequestPermissionItem();m_PermissionCallbacks = new PermissionCallbacks();//对系统权限处理的回调m_PermissionCallbacks.PermissionGranted += OnPermissionGranted;m_PermissionCallbacks.PermissionDenied += OnPermissionDenied;}/// <summary>/// 取消权限监听/// </summary>private void UnRegisterPermissionListener(){m_PermissionCallbacks.PermissionGranted -= OnPermissionGranted;m_PermissionCallbacks.PermissionDenied -= OnPermissionDenied;m_PermissionCallbacks = null;OnAllPermissionGrantedAction = null;m_RequestPermissionItemLst.Clear();m_RequestPermissionItemLst = null;}/// <summary>/// 权限授予事件/// </summary>/// <param name="Permission"></param>private void OnPermissionGranted(string Permission){MainThreadQueue.Instance.ExecuteQueue.Enqueue(() =>{Debug.Log(TAG+"OnPermissionGranted():" + Permission);// 继续请求其他权限CheckRequestPermissionLst();});}/// <summary>/// 权限拒绝事件/// </summary>/// <param name="Permission"></param>private void OnPermissionDenied(string Permission){MainThreadQueue.Instance.ExecuteQueue.Enqueue(() =>{Debug.Log(TAG + "OnPermissionDenied():" + Permission);// Todo 提示:1、打开失败页界面;2、然后可以继续请求权限});}/// <summary>/// 添加权限申请判断/// </summary>private void AddRequestPermissionItem() {m_RequestPermissionItemLst = new List<IRequestPermissionItem>();// 相机权限获取m_RequestPermissionItemLst.Add(new CameraRequestPermissionItem());// 麦克风权限获取m_RequestPermissionItemLst.Add(new MicrophoneRequestPermissionItem());// 继续添加更多...}/// <summary>/// 判断是否有权限没有申请/// </summary>/// <returns></returns>private bool JudgeIsHasPermission() {if (m_RequestPermissionItemLst == null) return true;else {foreach (var item in m_RequestPermissionItemLst){if (item.IsHasPermission == false) return false;}}return true;}#endregion
}

2、CameraRequestPermissionItem


using UnityEngine.Android;public class CameraRequestPermissionItem : BaseRequestPermissionItem
{/// <summary>/// TAG/// </summary>protected override string TAG { get; } = "[CameraRequestPermissionItem] ";/// <summary>/// 去申请的权限名称/// </summary>public override string ToRequestPermissionName => Permission.Camera;
}

3、MicrophoneRequestPermissionItem

using UnityEngine.Android;public class MicrophoneRequestPermissionItem : BaseRequestPermissionItem
{/// <summary>/// TAG/// </summary>protected override string TAG { get; } = "[MicrophoneRequestPermissionItem] ";/// <summary>/// 去申请的权限名称/// </summary>public override string ToRequestPermissionName => Permission.Microphone;
}

4、BaseRequestPermissionItem


using UnityEngine;
using UnityEngine.Android;public class BaseRequestPermissionItem : IRequestPermissionItem
{#region Data/// <summary>/// TAG/// </summary>protected virtual string TAG { get; } = "[BaseRequestPermissionItem] ";/// <summary>/// 去申请的权限名称/// </summary>public virtual string ToRequestPermissionName => Permission.Camera;/// <summary>/// 判断是否有权限/// </summary>public virtual bool IsHasPermission => Permission.HasUserAuthorizedPermission(ToRequestPermissionName);#endregion#region Interface function/// <summary>/// 请求权限/// </summary>/// <param name="permissionCallbacks">权限回调事件</param>public virtual void RequestPermission(PermissionCallbacks permissionCallbacks){if (permissionCallbacks == null) {Debug.LogError(TAG + " RequestPhoneStatePermission() permissionCallbacks is null ");return;}if (!IsHasPermission){Debug.Log(TAG+ " RequestPhoneStatePermission() ");Permission.RequestUserPermission(ToRequestPermissionName, permissionCallbacks);}}#endregion
}

5、IRequestPermissionItem

using UnityEngine.Android;public interface IRequestPermissionItem 
{/// <summary>/// 去申请的权限名称/// </summary>string ToRequestPermissionName { get; }/// <summary>/// 请求权限/// </summary>/// <param name="permissionCallbacks">权限回调事件</param>void RequestPermission(PermissionCallbacks permissionCallbacks);/// <summary>/// 判断是否有权限/// </summary>bool IsHasPermission { get; }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第三方软件检测机构要具备哪些资质要求?专业测试报告如何申请?

第三方软件检测机构是独立于软件开发商和用户之外的公正机构&#xff0c;负责对软件进行全面的检测和评估。其独立性保证了评测结果的客观性和公正性&#xff0c;有效避免了软件开发商对自身产品的主观偏见和误导。 要成为一家合格的第三方软件检测机构&#xff0c;需要具备一…

OKR 实践:来自一位信息技术部主管的成功秘诀

OKR 实践&#xff1a;来自一位信息技术部主管的成功秘诀 为什么选择OKR 公司信息技术部为38个各地分公司、12,000名员工的IT需求提供服务。庞大而多样的客户群常常使我们的团队分散&#xff0c;许多团队都在各自为政&#xff0c;以个案为基础解决问题&#xff0c;而不是采用企业…

LabVIEW高低温试验箱控制系统

要实现LabVIEW高低温试验箱控制系统&#xff0c;需要进行硬件配置、软件设计和系统集成&#xff0c;确保LabVIEW能够有效地监控和控制试验箱的温度。以下是详细说明&#xff1a; 硬件配置 选择合适的试验箱&#xff1a; 确定高低温试验箱的型号和品牌。 确认试验箱是否支持外…

摸鱼大数据——Hive表操作——文件数据的导入和导出

数据导入和导出 1、文件数据导入 1.1 直接上传文件 window页面上传 需求: 已知emp1.txt文件在windows/mac系统,要求使用hdfs保存此文件 并且使用hivesql建表关联数据 use day06; ​ -- 1- 创建Hive表 create table emp1 (id int,name string,salary int,dept string )row for…

基于51单片机的汽车智能灯光控制系统

一.硬件方案 本设计硬件部分&#xff0c;中央处理器采用了STC89C52RC单片机&#xff0c;另外使用两个灯珠代表远近光灯&#xff0c;感光部分采用了光敏电阻&#xff0c;因为光敏电阻输出的是电压模拟信号&#xff0c;单片机不能直接处理模拟信号&#xff0c;所以经过ADC0832进…

基于python flask +pyecharts实现的气象数据可视化分析大屏

背景 气象数据可视化分析大屏基于Python Flask和Pyecharts技术&#xff0c;旨在通过图表展示气象数据的分析结果&#xff0c;提供直观的数据展示和分析功能。在当今信息化时代&#xff0c;气象数据的准确性和实时性对各行业具有重要意义。通过搭建气象数据可视化分析大屏&…

【kubernetes】关于k8s集群如何将pod调度到指定node节点(亲和与反亲和等)

目录 一、调度约束 1.1K8S的 List-Watch 机制 ⭐⭐⭐⭐⭐ 1.1.1Pod 启动典型创建过程 二、调度过程 2.1Predicate&#xff08;预选策略&#xff09; 常见的算法 2.2priorities&#xff08;优选策略&#xff09;常见的算法 三、k8s将pod调度到指定node的方法 3.1指定…

Java | Leetcode Java题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> ans new LinkedList<List<Integer>>();if (root null) {return ans;}Queue<TreeNode> n…

SYD881X HID工程重连后连接参数没有更新功耗下不来

SYD881X HID工程重连后连接参数没有更新功耗下不来 现在测试到一个问题,第一次连接上的时候过一段时间功耗会下来到100UA以内,这个是正常的,但是关掉手机蓝牙再打开手机蓝牙就发现功耗是500UA左右下不来了! 抓包发现第一次连接和重连的时候手机给的连接参数是一样的: 问题是当…

电力电子技术03 (1)---电路稳态分析方法

学习来源&#xff08;只用于个人学习笔记&#xff0c;建议对着老师视频学习理解更深入&#xff09;&#xff1a;2.2稳态分析的基本方法_哔哩哔哩_bilibili 一、Buck降压电路 Buck电路&#xff0c;也称为降压转换器&#xff0c;是一种DC-DC电压转换器&#xff0c;用于将输入电…

代码随想录算法训练营第四十六天||139.单词拆分

一、139.单词拆分 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 示例 1&#xff1a; 输入: s …

【强训笔记】day25

NO.1 思路&#xff1a;哈希质数判断。 代码实现&#xff1a; #include <iostream> #include<string> #include<cmath> using namespace std;bool isprime(int n) {if(n<2) return false;for(int i2;i<sqrt(n);i){if(n%i0) return false;}return true…

2024-5-28 石群电路-16

2024-5-28&#xff0c;星期二&#xff0c;20:14&#xff0c;天气&#xff1a;晴&#xff0c;心情&#xff1a;晴。今天没有什么特别的事情发生&#xff0c;不过返校假期已经开始啦&#xff0c;和女朋友逛了街&#xff0c;吃了好吃的&#xff0c;学习也当然不能落下啦&#xff0…

BIO/NIO学习

在传送文件的时候常常出现这么一个问题&#xff0c;就是当客户端的文件全部传送完了之后&#xff0c;服务器没有接收到客户端那边传过的停止信号&#xff0c;所以服务器也就跟着客户端停止运行了&#xff0c;我们可以使用 try {socket.shutdownOutput();} catch (IOException e…

web前端之vue动态访问静态资源、静态资源的动态访问、打包、public、import、URL、Vite

MENU 静态资源与打包规则动态访问静态资源直接导入将静态资存放在public目录中动态导入URL构造函数结束语实践与坑附文 静态资源与打包规则 介绍 Vite脚手架在打包代码的时候&#xff0c;会把源代码里对于静态资源的访问路径转换为打包后静态资源文件的路径。主要的区别是文件指…

记录一次开源 MaxKey 安装部署

官方文档&#xff1a;https://www.maxkey.top/doc/docs/intro/ 开源代码&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey 发行版&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey/releases 一、准备工作 yum install -y yum-utils yum-config-manager --add-r…

SwiftUI初探

SwiftUI 虽然出现了好几年(1.0好像2019年出的&#xff0c;还有SPM也是同一年)&#xff0c;现在已经到从1.0到5.0&#xff0c;但受限于对系统的要求(最低iOS13.0,有的要求17.0及以上)&#xff0c;每个版本里面差异也很大&#xff0c;语法和Flutter 的Dart 比较像。空闲之余可以先…

5、sqlmap注入post类型+os-shell

题目&#xff1a;青少年&#xff1a;Easy_SQLi 1、打开网页&#xff0c;是一个登入表单 2、判断注入类型&#xff0c;是一个字符注入&#xff0c;使用or直接绕过密码进去了 3、上bp抓取数据包&#xff0c;sqlmmap用post注入走一遍&#xff0c;找到数据库&#xff0c;账号密码&…

如何制定一个有效的现货黄金投资策略(EEtrade)

制定一个有效的现货黄金投资策略涉及多方面的考量。以下是几个步骤和考虑因素&#xff0c;可以帮助您建立一个坚实的投资策略&#xff1a; 1. 设立清晰的投资目标 决定您投资现货黄金的主要目的。是否是为了短期利润&#xff0c;长期保值增值&#xff0c;还是为了投资组合的多…

N的阶乘(高精度)

目录 题目描述 输入格式 输出格式 样例输入 样例输出 思路 参考代码 题目描述 输入正整数n&#xff0c;输出n&#xff01; 输入格式 一个正整数n&#xff0c;n 3000 输出格式 输出n&#xff01; 样例输入 3 样例输出 9 思路 主要就是高精度乘法的模版&#x…