可以看出6.0之后的手机,针对targetSdkVersion是否高于23做了不同处理,如果targetSdkVersion>=23支持动态权限管理,那就更新动态权限,并将其持久化到runtime-permission.xml中,并更新其granted值,如果targetSdkVersion<23 ,也即是不知道6.0的动态管理,那就只更新AppOps,这是4.3引入的老的动态权限管理模型,不过这里主要是将权限持久化到appops.xml中,不过对于其granted的值是没有做任何更新的,仅仅是更新了packages.xml中的flag,这个flag可以配合appops.xml标识是否被授权(对于targetSdkVersion<23的适用),以上就是为什么context checkSelfPermission会失效的原因,涉及代码很多,不一一列举,对于取消授权revokeRuntimePermissions函数,模型一样,不在赘述,那下面看第二个问题,如何检查targetSdkVersion<23 app 在6.0以上手机的权限呢? Google给了一个兼容类PermissionChecker,这个类可以间接使用AppOpsService那一套逻辑,获取到权限是否被授予。
targetSdkVersion < 23 的时候,如何判断6.0的手机是否被授权
targetSdkVersion < 23的时候,6.0权限检查API失效了,不过通过上面的分析指导,在设置中权限的操作仍然会被存储内存及持久化到appops.xml文件中,这里就是走的AppOpsService那一套,AppOpsService可以看做6.0为了兼容老APP而保留的一个附加的权限管理模型,在6.0之后的系统中,可以看做runtime权限管理的补充,其实AppOpsService这套在4.3就推出了,不过不太灵活,基本没啥作用,之前只用到了通知管理。看一下Google提供的一个兼容类PermissionChecker如何做的:
public static int checkPermission(@NonNull Context context, @NonNull String permission,
int pid, int uid, String packageName) {
if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
return PERMISSION_DENIED;
}
String op = AppOpsManagerCompat.permissionToOp(permission);
if (op == null) {
return PERMISSION_GRANTED;
}
if (AppOpsManagerCompat.noteProxyOp(context, op, packageName)
!= AppOpsManagerCompat.MODE_ALLOWED) {
return PERMISSION_DENIED_APP_OP;
}
return PERMISSION_GRANTED;
}
对于6.0之后的手机AppOpsManagerCompat.noteProxyOp会调用AppOpsManager23的noteProxyOp,
private static class AppOpsManagerImpl {
public String permissionToOp(String permission) {
return null;
}
public int noteOp(Context context, String op, int uid, String packageName) {
return MODE_IGNORED;
}
public int noteProxyOp(Context context, String op, String proxiedPackageName) {
return MODE_IGNORED;
}
}
private static class AppOpsManager23 extends AppOpsManagerImpl {
@Override
public String permissionToOp(String permission) {
return AppOpsManagerCompat23.permissionToOp(permission);
}
@Override
public int noteOp(Context context, String op, int uid, String packageName) {
return AppOpsManagerCompat23.noteOp(context, op, uid, packageName);
}
@Override
public int noteProxyOp(Context context, String op, String proxiedPackageName) {
return AppOpsManagerCompat23.noteProxyOp(context, op, proxiedPackageName);
}<