PermissionX 1.7发布,全面支持Android 13运行时权限

Posted guolin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PermissionX 1.7发布,全面支持Android 13运行时权限相关的知识,希望对你有一定的参考价值。

本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新。

各位小伙伴们大家早上好。

一年一度的PermissionX升级又来了。

还记得上次发布PermissionX 1.6版本还是在去年10月份的时候,当时是对android 12系统进行了支持。详情可以参考这篇文章 PermissionX 1.6发布,支持Android 12,可能是今年最大的版本升级

而如今一年一晃而过,Android 13也已经正式发布了。

今年的Android 13在运行时权限变更方面变化较大,为此PermissionX在1.7版本也进行了诸多适配,并已全面支持Android 13系统。

如果你想要非常详细地了解Android 13运行时权限具体有哪些变更,可以参考我之前写的这篇文章 Android 13运行时权限变更一览

本篇文章,我们将聚焦在,如何使用新版的PermissionX来轻松地请求Android 13上的新增运行时权限。

那么Android 13上一共有哪些新增运行时权限呢?

我这里做了下统计,一共新增了6个运行时权限,如下所示:

READ_MEDIA_IMAGES
READ_MEDIA_VIDEO
READ_MEDIA_AUDIO
POST_NOTIFICATIONS
BODY_SENSORS_BACKGROUND
NEARBY_WIFI_DEVICES

这种幅度的改动已经算是非常大了。要知道,Android 12只新增了4个运行时权限,Android 11甚至没有新增任何运行时权限。

其实如果仅从简单的方面来讲,一个权限请求框架并不需要对每个版本新增的运行时权限做什么适配,因为运行时权限请求的方式都是同样的。

但PermissionX不是一个简单的权限请求框架,而是设计了一套完整的权限请求流程。包括权限被用户拒绝时要如何提醒用户,被永久拒绝时要如何引导用户手动开启权限,以及一些特殊权限的特殊处理。

这些都导致了PermissionX必须对每个系统版本进行额外的适配才行,但好处就是,开发者在使用的过程当中将会变得更加轻松,从而不需要自己再去做这些适配工作了。

那么接下来我们就来看一下,PermissionX是如何对上述6个新增运行时权限进行适配的。


细化的媒体权限

从Android 13开始,如果你的应用targetSdk指定到了33或以上,那么READ_EXTERNAL_STORAGE权限就完全失去了作用,申请它将不会产生任何的效果。

与此相对应地,Google新增了READ_MEDIA_IMAGES、READ_MEDIA_VIDEO和READ_MEDIA_AUDIO这3个运行时权限,分别用于管理手机的照片、视频和音频文件。

也就是说,以前只要申请一个READ_EXTERNAL_STORAGE权限就可以了。现在不行了,得按需申请,用户从而能够更加精细地了解你的应用到底申请了哪些媒体权限。

而使用PermissionX申请这3个权限非常简单。首先在AndroidManifest.xml文件中进行如下声明:

<manifest ...>
    <!-- Required only if your app targets Android 13. -->
    <!-- Declare one or more the following permissions only if your app needs
    to access data that's protected by them. -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- Required to maintain app compatibility. -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                     android:maxSdkVersion="32" />
    <application ...>
        ...
    </application>
</manifest>

这里的意思是,在Android 12及以下,仍然使用READ_EXTERNAL_STORAGE权限,在Android 13及以上则使用READ_MEDIA_IMAGES、READ_MEDIA_AUDIO和READ_MEDIA_VIDEO权限。

然后在代码中使用如下写法来申请这3个权限即可:

val requestList = ArrayList<String>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 
    requestList.add(Manifest.permission.READ_MEDIA_IMAGES)
    requestList.add(Manifest.permission.READ_MEDIA_AUDIO)
    requestList.add(Manifest.permission.READ_MEDIA_VIDEO)

if (requestList.isNotEmpty()) 
    PermissionX.init(activity)
        .permissions(requestList)
        .onExplainRequestReason  scope, deniedList ->
            val message = "PermissionX需要您同意以下权限才能正常使用"
            scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
        
        .request  allGranted, grantedList, deniedList ->
            if (allGranted) 
                Toast.makeText(activity, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
             else 
                Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
            
        

PermissionX允许一次性传入任意多个权限,然后批量向用户进行申请。这里我们将3个权限全部都传进去了。

需要说明的是,READ_MEDIA_IMAGES和READ_MEDIA_VIDEO这两个权限同属于一个权限组,READ_MEDIA_AUDIO属于另外一个权限组。

Android系统规定,同一个权限组中的权限,只要授予了其中一个,同组的其他权限也就都自动授予了。

因此,虽然这里我们申请了3个权限,但是只会看到两次请求弹窗,如下图所示:

可以看到,在两次权限请求弹窗当中,我们同意了一个,拒绝了另外一个。PermissionX此时会自动弹出一个解释弹窗,告知用户为什么这个权限是必要的,并引导用户再次授权。

其实想要适配好这种逻辑是需要写很多额外代码的,而PermissionX帮我们都自动封装了,权限请求就变得简单多了。


通知权限

通知权限可以说是Android 13的重磅功能之一。

在过去,任何一个应用想要发出通知的话都是不需要经过用户同意的,想发就能发。这就使得我们的手机通知栏经常被一些垃圾通知占领,真正重要的通知反而可能很难被找到。

这次Android 13则把通知纳入了运行时权限管理,也就是说,以后想要发送通知,得要先经过用户同意授权才行了。

对于用户而言,这确实是非常友善的功能,以后就不用担心再被各种垃圾通知所骚扰了。但是对于开发者而言,这个功能反而使得我们的适配工作变得各加困难。

因为在Android 13以下的系统,虽然应用程序可以不经过用户同意就发送通知,但是用户也有权力去屏蔽任何应用程序的通知,效果等同于用户拒绝了通知权限。

那么为了防止用户屏蔽掉了一些重要通知,某些应用的做法是主动检测通知是否被屏蔽,如果屏蔽的话就引导用户去设置页面手动开启。

而Android 13引入通知权限之后,以前的写法就不行了。所以开发者需要为Android 13以上和以下的系统分别进行适配才可以,无形中增加了开发的工作量。

因此,PermissionX 1.7版本在设计的时候就充分考虑到了这个问题,目标就是使得开发者的接入工作尽可能地最简单化。

下面我们就来看看使用PermissionX具体要如何申请通知权限,首先在AndroidManifest.xml文件中进行如下声明:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

然后在代码中使用如下写法来申请POST_NOTIFICATIONS权限即可:

PermissionX.init(activity)
    .permissions(PermissionX.permission.POST_NOTIFICATIONS)
    .onExplainRequestReason  scope, deniedList ->
        val message = "PermissionX需要您同意以下权限才能正常使用"
        scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
    
    .request  allGranted, grantedList, deniedList ->
        if (allGranted) 
            Toast.makeText(activity, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
         else 
            Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
        
    

没错,代码就是这么简单。

注意这里一个非常关键的细节,我们并没有使用Manifest.permission.POST_NOTIFICATIONS,而是使用了PermissionX.permission.POST_NOTIFICATIONS。

这是因为POST_NOTIFICATIONS是Android 13的新增权限,以前的系统版本是没有的,因此如果使用Manifest.permission.POST_NOTIFICATIONS在Android 13以下系统可能会导致编译不过。

而刚才我又说了,PermissionX为了简化开发者的适配工作,将Android 13以下的通知权限也一并处理了。因此,上述代码在所有的Android版本上都可以正常工作。

那么我们先来看一下上述代码在Android 13上的运行效果,如下图所示:

可以看到,这里会直接向用户申请通知权限,如果用户选择了拒绝,那么会再弹出一个PermissionX的提示框,告诉用户为什么我们需要这个权限。

然后再来看一下上述代码在Android 12上的运行效果。

需要注意还有一个细节,每个应用程序的通知开关在Android 12及以下系统都是默认开启的。这也是前面为什么说任何应用想要发送通知是不需要经过用户同意的,想发就能发。

因此为了验证上述代码是否能正常工作,我们还得先手动把当前应用的通知开关给关掉才行,如下图所示:

接下来验证效果如下:

可以看到,这里首先会弹出一个PermissionX的提示框,提醒用户需要手动打开设置当中的通知开关才行。

只要用户点击了同意,那么就会一键跳转到当前应用的通知设置界面,让用户用最低的操作成本来打开通知开关。

而这一系列功能只需要写上述一份代码就可以实现了,这就是PermissionX给开发者所带来的便利性。


后台运动传感器权限

还有一个变化是运动传感器权限。

之前我们如果想要读取手机运动传感器的数据,需要申请BODY_SENSORS权限。而在Android 13当中,Google给BODY_SENSORS权限又添加了一个只能在前台使用的限定。

可以看到,在Android 13上申请BODY_SENSORS权限时,用户只能授权在前台使用。

那么如果我们的应用程序就是要在后台获取运动传感器数据怎么办呢?这个时候就需要用到Android 13上另一个新增的运行时权限,BODY_SENSORS_BACKGROUND。

但是根据我的测试,申请BODY_SENSORS_BACKGROUND这个权限的坑非常多。

首先,申请BODY_SENSORS_BACKGROUND权限之前必须得要先获得BODY_SENSORS授权才行,不然申请就是无效的,会被直接拒绝。这个设定有点像当初Android 10增加后台获取地理位置权限的设定。

其次,BODY_SENSORS和BODY_SENSORS_BACKGROUND权限还不可以同时一起申请,不然的话两个权限会一同被拒绝。这种奇怪的设定我也是第一次见。

所以正确的做法是,要先申请BODY_SENSORS权限,在这个权限获得授权之后,再去申请BODY_SENSORS_BACKGROUND才行。

那么,你的脑海中是否已经勾勒出代码应该怎么写了呢?

不用费脑子了,因为PermissionX已经帮我们把这些适配逻辑都处理好了。

使用PermissionX来申请运动传感器权限,只需要把BODY_SENSORS和BODY_SENSORS_BACKGROUND一同传给PermissionX即可。

我们还是通过代码来验证一下,首先在AndroidManifest.xml中对这两个权限进行声明:

<manifest ...>
    <uses-permission android:name="android.permission.BODY_SENSORS"/>
    <uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND"/>
    <application ...>
        ...
    </application>
</manifest>

接下来使用如下代码来申请运动传感器权限即可:

val requestList = ArrayList<String>()
requestList.add(Manifest.permission.BODY_SENSORS)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 
    requestList.add(Manifest.permission.BODY_SENSORS_BACKGROUND)

PermissionX.init(activity)
    .permissions(requestList)
    .onExplainRequestReason  scope, deniedList ->
        val message = "PermissionX需要您同意以下权限才能正常使用"
        scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
    
    .request  allGranted, grantedList, deniedList ->
        if (allGranted) 
            Toast.makeText(activity, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
         else 
            Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
        
    

PermissionX在内部做的事情其实就是我们上述分析的内容。先申请BODY_SENSORS权限,在这个权限获得授权之后,再去申请BODY_SENSORS_BACKGROUND。但是由于框架内部做好了封装,我们再去编写申请权限的代码就可以变得非常简洁了。

来看一下运行效果吧,如下图所示:

可以看到,这里一开始只会申请前台的运动传感器权限。当用户选择了While using the app之后,PermissionX会弹出一个提醒框,告诉用户还需要同意后台运动传感器权限才行。之后会直接带用户来到当前应用程序的运动传感器权限设置界面,点击Allow all the time即可完成授权。

整个流程其实非常繁琐,但是Google就是这样设计的。可能也是故意搞得繁琐一点,让用户更加注重保护自己的隐私,而不是简单一键就把所有权限统统都交给这些应用程序了。

而PermissionX则在Android 13规则允许的前提下,将权限申请流程以及申请代码书写都尽可能做到了最简化。让普通用户和开发者都能享受到更好的用户体验。


附近WiFi设备权限

去年,Google在Android 12当中新增了几个蓝牙相关的运行时权限。原因是因为当开发者去访问一些蓝牙相关的接口时,却需要申请地理位置权限才行,这就让一些对隐私敏感的用户非常反感。

这是一个历史遗留问题,为了更好地保护用户隐私,Google在Android 12当中增加了BLUETOOTH_SCAN,BLUETOOTH_ADVERTISE,BLUETOOTH_CONNECT,这3个运行时权限。这样当开发者需要访问蓝牙相关的接口时,只需要请求这些蓝牙权限即可。

而在今年的Android 13当中,Google将保护用户隐私延伸到了WIFI领域。

和蓝牙类似,当开发者去访问一些WIFI相关的接口时,如热点、WIFI直连、WIFI RTT等,也需要申请地理位置权限才行。

这其实也是一个历史遗留问题,用户肯定无法理解为什么使用一些WIFI功能时却需要授权地理位置权限。

为此,Android 13当中新增了一个NEARBY_WIFI_DEVICES权限,当再使用以上场景相关的WIFI API时,我们只需申请NEARBY_WIFI_DEVICES权限即可,从而更好地保护了用户的隐私。

这是一个非常普通的运行时权限,PermissionX并没有对它进行任何适配,也没有什么坑点,需要申请它的时候直接去申请即可。

AndroidManifest.xml文件中的声明如下:

<manifest ...>
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"/>
    <application ...>
        ...
    </application>
</manifest>

权限申请代码示例如下:

PermissionX.init(activity)
    .permissions(Manifest.permission.NEARBY_WIFI_DEVICES)
    .onExplainRequestReason  scope, deniedList ->
        val message = "PermissionX需要您同意以下权限才能正常使用"
        scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
    
    .request  allGranted, grantedList, deniedList ->
        if (allGranted) 
            Toast.makeText(activity, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
         else 
            Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
        
    

运行效果图如下:

都是非常标准和基础的写法,我就不做更多解释了。


如何升级

关于PermissionX新版本的内容变化就介绍到这里,升级的方式非常简单,修改一下dependencies当中的版本号即可:

repositories 
  google()
  mavenCentral()


dependencies 
    implementation 'com.guolindev.permissionx:permissionx:1.7.1'

如果你对PermissionX的源码感兴趣,可以访问PermissionX的项目主页:

https://github.com/guolindev/PermissionX

另外,本篇文章主要介绍的是PermissionX 1.7版本的新特性。如果你之前并没有接触过PermissionX,可以通过我编写的《PermissionX权限系列专栏》逐步进行学习,里面有非常详尽的用法讲解。

如果想要学习Kotlin和最新的Android知识,可以参考我的新书 《第一行代码 第3版》点击此处查看详情

以上是关于PermissionX 1.7发布,全面支持Android 13运行时权限的主要内容,如果未能解决你的问题,请参考以下文章

PermissionX 1.7发布,全面支持Android 13运行时权限

PermissionX 1.5发布,支持申请Android特殊权限啦

PermissionX 1.5发布,支持申请Android特殊权限啦

PermissionX 1.5发布,支持申请Android特殊权限啦

PermissionX 1.6发布,支持Android 12,可能是今年最大的版本升级

PermissionX 1.6发布,支持Android 12,可能是今年最大的版本升级