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 判断用户之前对申请权限做出的相应动作。

相关推荐
昊虹AI笔记32 分钟前
PHP中类名加双冒号的作用
android·java·php
ShanLiang_Build1 小时前
Android 使用Charles抓包显示Unknown
android
逃课的小学生1 小时前
android 安全sdk相关
android
今人不见古时月,今月曾经照古人2 小时前
android studio Terminal控制台命令打包 apk
android·ide·android studio
Winston Wood2 小时前
Android 图形系统之一:概览
android·图形系统
柯南二号2 小时前
Android 实现双列图片瀑布流式布局
android·recycleview·瀑布流
manok2 小时前
Android - 权限管理漏洞
android·sast·静态分析规则
冷眼看人间恩怨2 小时前
【Android】AnimationDrawable帧动画的实现
android·帧动画
所待.3833 小时前
MySQL之视图
android·数据库·mysql
Lsx-codeShare4 小时前
Uniapp 安装安卓、IOS模拟器并调试
android·前端·javascript·ios·微信小程序·小程序·uni-app