市面上权限请求的库很多,而前段时间官方刚刚将 requestPermissions() + onRequestPermissionsResult() API 弃用,那么官方的替代方案是什么呢?本文将介绍 Activity Result API 进行权限请求的使用以及如何借助 Kotlin 扩展函数自己封装一个权限请求库
在 Android Jetpack Activity 1.2.0-alpha02 和 Fragment 1.3.0-alpha02 中,Google 提供了全新的 Activity Result API 来替换 startActivityForResult() + onActivityResult()和 requestPermissions() + onRequestPermissionsResult()。详情可移步 官方文档[1],中文可以参考 秉心说[2] 的 是时候丢掉 onActivityResult 了 ![3],有些 API 的名字发生了变化,请留意
紧接着在 Activity 1.2.0-alpha04 和 Fragment 1.3.0-alpha04 版本中,
startActivityForResult()+onActivityResult()和requestPermissions()+onRequestPermissionsResult()被标记为弃用,而在Fragment 1.3.0-alpha05 这些标记弃用的方法内部已改为使用 ActivityResultRegistry 实现
新的 API 使用非常简单,分为单一权限请求,和多权限请求,Activity 和 Fragment 使用方法相同
配合 Kotlin 的扩展函数,我们可以将权限请求的逻辑进行封装。
开发过程中,我们申请权限时关注的就是权限是否申请成功,如果未申请成功是否勾选了不再询问
因此我们可以加入「权限申请成功」,「权限申请失败且未勾选不再询问」,「权限申请失败且已勾选不再询问」三种状态的回调
/** * [permission] 权限名称 * [granted] 申请成功 * [denied] 被拒绝且未勾选不再询问 * [explained] 被拒绝且勾选不再询问 */ inline fun Fragment.requestPermission( permission: String, crossinline granted: (permission: String) -> Unit = {}, crossinline denied: (permission: String) -> Unit = {}, crossinline explained: (permission: String) -> Unit = {} ) { registerForActivityResult(ActivityResultContracts.RequestPermission()) { result -> when { result -> granted.invoke(permission) shouldShowRequestPermissionRationale(permission) -> denied.invoke(permission) else -> explained.invoke(permission) } }.launch(permission) } /** * [permissions] 权限数组 * [allGranted] 所有权限均申请成功 * [denied] 被拒绝且未勾选不再询问,同时被拒绝且未勾选不再询问的权限列表 * [explained] 被拒绝且勾选不再询问,同时被拒绝且勾选不再询问的权限列表 */ inline fun Fragment.requestMultiplePermissions( vararg permissions: String, crossinline allGranted: () -> Unit = {}, crossinline denied: (List<String>) -> Unit = {}, crossinline explained: (List<String>) -> Unit = {} ) { registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: MutableMap<String, Boolean> -> //过滤 value 为 false 的元素并转换为 list val deniedList = result.filter { !it.value }.map { it.key } when { deniedList.isNotEmpty() -> { //对被拒绝全选列表进行分组,分组条件为是否勾选不再询问 val map = deniedList.groupBy { permission -> if (shouldShowRequestPermissionRationale(permission)) DENIED else EXPLAINED } //被拒接且没勾选不再询问 map[DENIED]?.let { denied.invoke(it) } //被拒接且勾选不再询问 map[EXPLAINED]?.let { explained.invoke(it) } } else -> allGranted.invoke() } }.launch(permissions) }使用起来是这样的
Java 是可以调用 Kotlin 的扩展函数的,为了更方便地调用,可以在此基础上再封装一层
demo 在这里[4],如果感觉这个思路对你有帮助的话,点一颗小星星吧~ ????
另外我还将它传到了 JitPack 上,现已支持 Kotlin DSL 写法,引入姿势如下:
在项目根目录的 build.gradle 加入
allprojects { repositories { //... maven { url 'https://jitpack.io' } } }添加依赖
dependencies { implementation 'com.github.Flywith24:Flywith24-Permission:$version' }我是 Flywith24[5],我的博客内容已经分类整理 在这里[6],点击右上角的 Watch 可以及时获取我的文章更新哦 ????
掘金[7]
简书[8]
Github[9]
[1]
官方文档: https://developer.android.com/training/basics/intents/result
[2]秉心说: https://juejin.im/user/586eff908d6d81005879507d
[3]是时候丢掉 onActivityResult 了 !: https://juejin.im/post/5e80cb1ee51d45471654fae7
[4]demo 在这里: https://github.com/Flywith24/Flywith24-Permission
[5]Flywith24: https://flywith24.gitee.io/
[6]在这里: https://github.com/Flywith24/BlogList
[7]掘金: https://juejin.im/user/57c7f6870a2b58006b1cfd6c
[8]简书: https://www.jianshu.com/u/3d5ad6043d66
[9]Github: https://github.com/Flywith24