Android 用协程实现更优雅的权限请求

先看使用示例,如果成功获取到权限,就会执行takePhoto方法,如果获取失败,就会直接返回,不执行后面的代码。

      GlobalScope.launch {
            PermissionUtilsKt().startCheck(PermissionUtils.PERMISSION_CAMERA)
            takePhoto()
        }

可以看到,只需要一行代码,就可以完成权限请求,且不需要回调(但处理“拒绝”的情况,还是使用到了回调),很好的提升了代码的可读性。

代码也很简单,最核心一点,是使用了 suspendCoroutine

此外,请求权限的逻辑是使用 com.blankj:utilcodex:1.30.6 实现的

class PermissionUtilsKt() {
    var callback: Callback? = null
    var permissionForeverDenyMsg = "请授予相关权限,否则功能无法正常使用"
    var permissions: MutableList<String> = ArrayList()
    fun setPermissionForeverDenyMsg(permissionForeverDenyMsg: String): PermissionUtilsKt {
        this.permissionForeverDenyMsg = permissionForeverDenyMsg
        return this
    }

    fun clearAllPermissions() {
        permissions.clear()
    }

    //循环检查每个权限
    fun isAllGranted(): Boolean {
        var isAllGranted = true
        //循环检查每个权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (permission in permissions) {
                if (ActivityUtils.getTopActivity()
                        .checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED
                ) {
                    isAllGranted = false
                    break
                }
            }
        }
        return isAllGranted
    }

    suspend fun startCheck(vararg permissions: String, callback: Callback) {
        this.callback = callback
        startCheck(*permissions)
    }

    suspend fun startCheck(vararg permissions: String) {
        this.permissions = permissions.toMutableList()

        //挂起协程
        suspendCoroutine<String> {
            PermissionUtils.permission(*permissions).callback(object : FullCallback {
                override fun onGranted(granted: List<String>) {
                    if (isAllGranted()) {
                        it.resume("")
                    } else {
                        //ToastUtil.showCenter("请授予相关权限");
                    }
                }

                override fun onDenied(deniedForever: List<String>, denied: List<String>) {
                    if (callback != null) {
                        if (shouldShowRequestPermissionRationale()) {
                            callback!!.onDeny()
                            //还可以再申请
                            //ToastUtil.showCenter("请授予相关权限");
                            //shouldShowRequestPermissionRationale 1,在允许询问时返回true ; 2,在权限通过 或者权限被拒绝并且禁止询问时返回false 但是有一个例外,就是重来没有询问过的时候,也是返回的false 所以单纯的使用shouldShowRequestPermissionRationale去做什么判断,是没用的,只能在请求权限回调后再使用。 Google的原意是: 1,没有申请过权限,申请就是了,所以返回false; 2,申请了用户拒绝了,那你就要提示用户了,所以返回true; 3,用户选择了拒绝并且不再提示,那你也不要申请了,也不要提示用户了,所以返回false; 4,已经允许了,不需要申请也不需要提示,所以返回false;
                        } else {
                            //有权限被永久拒绝了
                            callback!!.onDenyForever(permissionForeverDenyMsg)
                        }
                    }
                    it.context.cancel()
                }
            }).request()
        }

    }

    fun shouldShowRequestPermissionRationale(): Boolean {
        var shouldShow = false
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (permission in permissions) {
                if (ActivityUtils.getTopActivity()
                        .shouldShowRequestPermissionRationale(permission)
                ) {
                    shouldShow = true
                    break
                }
            }
        }
        return shouldShow
    }

    //内部静态类,需要父类加载后才会加载
    abstract class Callback {
        open fun onGranted() {}
        open fun onDeny() {}
        open fun onDenyForever(tipMsg: String?) {
            val snackbar = Snackbar.make(
                ActivityUtils.getTopActivity().window.decorView,
                tipMsg!!,
                Snackbar.LENGTH_LONG
            )
            snackbar.setAction(StringUtils.getString(R.string.qushezhi)) {
                val intent = Intent()
                intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                val uri = Uri.fromParts("package", ActivityUtils.getTopActivity().packageName, null)
                intent.data = uri
                ActivityUtils.getTopActivity().startActivity(intent)
            }
            snackbar.show()
        }
    }

    companion object {
        const val PERMISSION_READ_CONTACTS = Manifest.permission.READ_CONTACTS
        const val PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE
        const val PERMISSION_MANAGE_EXTERNAL_STORAGE = Manifest.permission.MANAGE_EXTERNAL_STORAGE
        const val PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE
        const val PERMISSION_CAMERA = Manifest.permission.CAMERA
        const val PERMISSION_RECORD_AUDIO = Manifest.permission.RECORD_AUDIO
        const val PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION
        const val PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION
        const val PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE
    }
}

下面展示下“拒绝”的情况。

如果请求被拒绝了,会执行回调,但不会继续执行下方的takePhoto()

      GlobalScope.launch {
                PermissionUtilsKt.startCheck(PermissionUtils.PERMISSION_CAMERA,callback= object : PermissionUtilsKt.Callback() {
                override fun onDeny() {

                }

                override fun onDenyForever(tipMsg: String?) {

                }
            })

        takePhoto()

        }

当然,也可以给startCheck加个返回值,然后通过返回值判断。(本文没有实现这种情况)

      GlobalScope.launch {
          val result =  PermissionUtilsKt.startCheck(PermissionUtils.PERMISSION_CAMERA)
          when(result){
             is Grante ->{takePhoto()}
             is Deny ->{return}
             is DenyForever ->{return}
          }
      }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值