一、说在前面
由于各个系统厂商定制,checkSelfPermission在有些机型上是始终为0的(也就是允许),这个问题非常头疼嘞,于是手持一加对三种方式进行了测试。
以read_sms权限为例
二、检查方式
- 常用的检查
ContextCompat.checkSelfPermission(context, permission)
println("self权限: $permissionState")
- ops系统检查
val op = AppOpsManager.permissionToOp(android.Manifest.permission.READ_SMS)
val appOpsManager = getSystemService(AppOpsManager::class.java)
val result = appOpsManager.noteProxyOp(op, packageName)
println("OPS权限: $result")
3.ops系统检查(方法已过时弃用了)
val appOpsManager = getSystemService(AppOpsManager::class.java)
val checkResult = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_FINE_LOCATION, Binder.getCallingUid(), packageName)
println("OPS2权限: $checkResult")
三、结果条件
- PackageManager结果
- PERMISSION_GRANTED 0: 允许
- PERMISSION_DENIED 1: 未允许
- ops结果
- AppOpsManager.MODE_ALLOWED 0: 允许
- AppOpsManager.MODE_IGNORED 1: 禁止
- AppOpsManager.MODE_ERRORED 2: 出错
- AppOpsManager.MODE_FOREGROUND 3: 询问
3.测试代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
//--------------------------------------------------------------------------------
val permissionState = checkSelfPermission(android.Manifest.permission.READ_SMS)
var smg = ""
when (permissionState) {
PackageManager.PERMISSION_GRANTED -> smg = "有权限"
PackageManager.PERMISSION_DENIED -> smg = "未获取权限"
}
println("self权限: $permissionState $smg")
//--------------------------------------------------------------------------------
val op = AppOpsManager.permissionToOp(android.Manifest.permission.READ_SMS)
val appOpsManager = getSystemService(AppOpsManager::class.java)
val result = appOpsManager!!.noteProxyOp(op, packageName)
var smg1 = ""
when (result) {
AppOpsManager.MODE_ALLOWED -> smg1 = "有权限"
AppOpsManager.MODE_IGNORED -> smg1 = "无权限"
AppOpsManager.MODE_ERRORED -> smg1 = "检查出错"
AppOpsManager.MODE_FOREGROUND -> smg1 = "询问"
}
println("OPS权限: $result $smg1")
//--------------------------------------------------------------------------------
val checkResult = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_FINE_LOCATION, Binder.getCallingUid(), packageName)
var smg2 = ""
when (result) {
AppOpsManager.MODE_ALLOWED -> smg2 = "有权限"
AppOpsManager.MODE_IGNORED -> smg2 = "无权限"
AppOpsManager.MODE_ERRORED -> smg2 = "检查出错"
AppOpsManager.MODE_FOREGROUND -> smg2 = "询问"
}
println("OPS2权限: $checkResult $smg2")
四、打印结果
1. 允许
一加5T 9.0.0
华为MATE8 9.0.0
小米MAX2 7.1.1
2. 禁止
一加5T
华为MATE8
小米MAX2
3. 询问
一加5T
小米MAX2 ,小米在这里自动弹出权限申请框
无操作后自动拒绝
选择允许后
五、结论
用了两款手机测试,上图很明显,appOpsManager.checkOpNoThrow可以直接废弃了,而另外两种方式可以结合使用进行交叉验证。
-
方式1在一加上只有允许权限生效了,小米正常(一加上一直如此,大部分系统没问题)
-
方式2判断非常准确,虽然只辨别出了有和无
- 权限状态分为三种(允许、禁止、询问)的机型
- 权限状态分为两种(允许、禁止)的机型
都可以使用前两种方式交叉验证,下面贴上代码。
fun hasPermission(context: Context, permission: String): Boolean {
if (!isOverMarshmallow()) {
// 系统版本小于6.0的机型
return true
}
//`````````````````````````````````````````````````````````````````
val permissionState = checkSelfPermission(context, permission)
println("self权限: $permissionState")
when (permissionState) {
PackageManager.PERMISSION_GRANTED -> println("有权限")
PackageManager.PERMISSION_DENIED -> println("未获取权限")
}
//`````````````````````````````````````````````````````````````````
val op = AppOpsManager.permissionToOp(permission)
val appOpsManager = context.getSystemService(AppOpsManager::class.java)
if (appOpsManager == null || TextUtils.isEmpty(op)) {
return true
}
val result = appOpsManager.noteProxyOp(op, context.packageName)
println("OPS权限: $result")
when (result) {
AppOpsManager.MODE_ALLOWED -> println("有权限")
AppOpsManager.MODE_IGNORED -> println("权限禁止")
AppOpsManager.MODE_ERRORED -> println("出错了")
AppOpsManager.MODE_FOREGROUND -> println("权限需要询问")
}
return result == AppOpsManager.MODE_ALLOWED && permissionState == PackageManager.PERMISSION_GRANTED
}