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

  • 相关阅读:
    RS485modbus转Profinet网关协议连接富凌DZB300系列变频器配置方法
    如何向mongoDB中添加新的字段附代码(全)
    计算机网络——传输层
    CentOS7如何安装图形界面
    微信安装包从0.5M暴涨到260M,为什么我们的程序越来越大?
    圆的面积为什么是π r²
    铁死亡化合物库
    C语言 宏定义使用方式
    GIT 中 SSH如何获取密钥
    ceph报错总结
  • 原文地址:https://blog.csdn.net/qq_44950283/article/details/134350955