Android 动态权限申请过程 --Android12
1.申请
申请前提,manifest一定要有,没有是不会通过的。
动态申请代码:
public final void requestPermissions(@NonNull String[] permissions, int requestCode)
启动一个供用户选择的授权界面:
final Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
创建intent的代码在PackageManager:
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
throw new IllegalArgumentException("permission cannot be null or empty");
}
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
intent.setPackage(getPermissionControllerPackageName());
return intent;
}
包名获取的逻辑在pms里面:
private @NonNull String getRequiredPermissionControllerLPr() {
final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
ResolveInfo resolveInfo = matches.get(0);
if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
throw new RuntimeException("The permissions manager must be a privileged app");
}
return matches.get(0).getComponentInfo().packageName;
} else {
throw new RuntimeException("There must be exactly one permissions manager; found "
+ matches);
}
}
这里注意下,获取的flag,然后就是获取的数量,必须是1,不是1直接异常,而且还是RuntimeException。
最后启动的参数就是:
pkg:com.android.permissioncontroller
action:android.content.pm.action.REQUEST_PERMISSIONS
那么启动的activity是哪个呢?
在源码位置是:
aosp/packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity
2.授予
上面界面启动以后,用户点击同意,兜兜转转最后到:
packageManager.grantRuntimePermission(group.packageName, perm.name, user)和 mPackageManager.updatePermissionFlags(String permName, String packageName,
int flagMask, int flagValues, UserHandle user)
最后的实现在:PermissionManagerService。
这里列出几个关键步骤,下面详细描述。
关键步骤:
1.READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE的处理逻辑。
这两个权限需要一些额外处理。主要是挂载什么的。
2.PermissionManagerService 里面有个默认的授权回调,在权限发生变化的时候会触发这个回调:private final PermissionCallback mDefaultPermissionCallback = new PermissionCallback();
然后调用:
mPackageManagerInt.writePermissionSettings(userIds, !sync); 这个就是写xml文件,表明app已经申请的权限,如果已经申请通过后面被关闭,这里也会有这一条,但是状态是false。
3.PermissionPolicyService 里面有注册一个动态权限变更的回调
这里需要注意下,这部分与Android11的有点不一样了。11在授权这里会计算gid变化,而且最后检测如果是读写sd卡相关,会直接通知 storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName)。
PermissionPolicyService
permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
注册动态权限变更回调。
final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
getUserContext(getContext(), UserHandle.of(userId)));
synchroniser.addPackage(pkg.packageName);
final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage(
pkg.packageName, userId);
for (String sharedPkgName : sharedPkgNames) {
final AndroidPackage sharedPkg = packageManagerInternal
.getPackage(sharedPkgName);
if (sharedPkg != null) {
synchroniser.addPackage(sharedPkg.getPackageName());
}
}
synchroniser.syncPackages();
shareUser都要处理。。。。
…未完待续