Android 动态权限申请过程

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都要处理。。。。

…未完待续

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值