当前位置: 首页 > news >正文

Android---动态权限适配问题

在 Android6.0,即 API 23 之前,App 需要的权限都会在安装阶段向用户展示,而在 App 运行期间不需要动态判断权限是否已申请。从 6.0 之后的版本开始,Android 系统做了一次大的改动。对于部分权限,App 需要在代码中动态申请相应的权限。

权限分类

Android 权限分两种:普通权限和危险权限。在两种权限都需要在 AndroidManifest.xml 清单文件中声明。

普通权限(Normal Permission):在程序运行时期自动获取,只需要在清单文件中声明。常用的是 INTERNET 网络权限。

危险权限(Dangerous Permission):App 中可能存在一些操作会查看与用户隐私相关的信息,比如查看用户的通讯录或者图库等。对于这一类操作,Android 系统要求 App 主动向用户展示操作所需要的权限。只有用户授权之后,才可以进行下一步操作。

权限动态申请流程

一次完整的权限申请流程,如下图所示

对上图申请流程做一个简单说明

首先,判断 API 版本是否小于 23。如果版本低于23,则不需要动态申请权限,否则调用 checkSelfPermission() 方法检查权限是否已申请。如果,checkSelfPermission 返回 false,说明权限并没有申请,此时需要调用 requestPermission() 方法,主动发送申请权限的操作。

shouldShowRequestPermissionRationale

在调用 requestPermission 方法申请权限之前,需要判断是否需要展示 shouldShowRequestPermissionRationale,该方法会返回以下两种情况:

1)返回 true。用户之前在申请权限操作时,点击了“拒绝”按钮,但是没有选择“Never ask again”选项。

2)返回 false。有两种情况会返回 false

a. 用户从来没有申请过次权限;

b. 用户之前选中拒绝,并且勾选了 “Never ask again”选项。

处理办法

针对返回 true 的情况,很容易处理。这种情况表示用户已经拒绝申请操作,但是并没有选中 “Never ask again” 选项。因此,我们只需要再次调用 requestPermission 方法申请权限即可。系统会自动弹出申请权限的对话框。

对于放回 false 的情况稍微麻烦一点,因为有两种情况会返回 false。针对着两种情况所对应的返回操作也不一样。

如果用户从来没有申请过次权限,那么就同上面返回 true 的情况一样,直接调用 requestPermission() 方法申请权限即可。如果是因为用户之前拒绝申请操作并且勾选了 “Never ask again” 选项,此时我们不应该再执行 requestPermission 方法。通过弹出自定义的对话框,提示用户此操作必须通过权限申请之后才可以继续进行,并给用户提供进入权限设置界面的入口。

注意:shouldShowRequestPermissionRationale 返回 true 的情况,在很多国内厂商的手机中设置了自动屏蔽,也就是没有返回 true 的情况,比如华为、小米手机。

代码演示

接下来以申请通讯录权限为例,来演示如何进行动态权限适配。

首先,判断系统版本是否高于23,代码如下

只有在API版本高于23的系统中,才需要动态申请权限。

在申请之前,还需要检查当前 App 是否已经获取到相应的权限,避免重复申请。如下所示

上图中的 PackageManager.PERMISSION_GRANTED 表示权限已经获取。接下来就是申请权限的流程

上文中已经介绍,在申请权限之前需要调用 shouldShowRequestPermissionRationale 判断用户之前的操作。因此代码修改如下

图中1处,shouldShowRequestPermissionRationale 返回 true,直接调用 requestPermissions 再次申请权限即可。但是,对于返回 false 的情况需要特殊处理,因为有两种情况返回 false。

可以借助于 SharedPreference 判断是否为用户第一次申请权限操作。代码如下所示

上图中使用 SharedPreference 来保存用户是否第一次申请权限的状态值,默认情况为 true。当执行一次权限申请后,调用 firstTimeAsking() 方法将其设置为 false。

权限申请操作封装

App 中会有很多调用危险权限的方法,如果每一次执行这些代码都复制粘贴上述这些权限申请的代码,会显得代码很冗余。因此,可以将动态权限申请的操作封装到工程中的某个 Util 类中,并提供给调用者相应的回调接口。部分核心代码如下

最后,只需要在 BaseActivity 中调用此方法时,传入具体实现的 PermissionRequestListener 即可。如下所示

第三方库使用

对于 Permission 的动态申请,也可以借助于开源的第三方库来加快开发速度。目前,对于 Permission 动态权限申请比较好的开源库有:a)Dexter;b)easypermissions;c)PermissionsDispatcher。

但是,第三方库的使用也具有一定的隐患。不同版本中 Android 系统对 Permission 的处理政策并不完全一致,在新版本的系统中很有可能会添加对权限申请更严格的请求策略。

比如,在 Android 10 中,增加了对外置存储访问的限制。正常情况下,我么可以通过以下代码获取外置存储的根路径,然后在此目录下创建 App 相应的文件缓存数据。

但是,从 Android 10(API 29)开始,App 层没有访问此路径的权限。无论在 AndroidManifest 文件中加上对应的权限,还是使用 ActivityCompact.requestPermissions 动态申请权限,都无法实现访问。目前官方提供的临时解决方案是在 AndroidManifest.xml 清单文件中添加如下设置

但是,如果我么使用的是第三方库处理动态权限申请操作,如果第三方库没有做版本适配,或者做了相应的适配修改,但是并没有升级第三方库的版本。都会造成在 Android 10 设备上处理文件发生异常

总结

本次主要介绍了 Android 系统中申请权限相关的知识点,主要是针对 Android 版本 23 之后的动态申请做了详细介绍。需要掌握的方法:1)checkSelfPermission 检查某权限是否已经申请;2)requestPermissions 主动发送申请权限的请求;3)shouldShowRequestPermissionRationale 判断用户之前对申请权限做出的相应动作。

相关文章:

  • Unity 下载Zip压缩文件并且解压缩
  • Android Rxjava架构原理与使用的详解解答
  • 【第2章 Node.js基础】2.3 Node.js事件机制
  • 【数学】Pair of Topics—CF1324D
  • Android各类View触摸监听器失效
  • 【GitHub】PR的学习笔记
  • bin、hex、ELF文件格式上的区别
  • Spring 常见面试题
  • 基于JavaWeb+SpringBoot+Vue摩托车商城微信小程序系统的设计和实现
  • STM32——NVIC中断优先级管理分析
  • springcloud旅游网站源码
  • 使用LLM-Tuning实现百川和清华ChatGLM的Lora微调
  • C_7练习题
  • 【计算机网络】UDP协议
  • JavaWeb篇_09——Tomcat运行过程以及Servlet继承结构
  • 收藏网友的 源程序下载网
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • Android交互
  • CAP理论的例子讲解
  • PV统计优化设计
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 给github项目添加CI badge
  • 记一次和乔布斯合作最难忘的经历
  • 聚类分析——Kmeans
  • Android开发者必备:推荐一款助力开发的开源APP
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • 如何正确理解,内页权重高于首页?
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • # centos7下FFmpeg环境部署记录
  • # 飞书APP集成平台-数字化落地
  • #if和#ifdef区别
  • #Java第九次作业--输入输出流和文件操作
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (02)vite环境变量配置
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (生成器)yield与(迭代器)generator
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (四)图像的%2线性拉伸
  • .NET Core Web APi类库如何内嵌运行?
  • .net 反编译_.net反编译的相关问题
  • .NET 药厂业务系统 CPU爆高分析
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .net操作Excel出错解决
  • .NET框架
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • .net专家(张羿专栏)
  • [ Linux ] Linux信号概述 信号的产生
  • [ 转载 ] SharePoint 资料