先看使用示例,如果成功获取到权限,就会执行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}
}
}