firefly给的android-12,已在这方面做了修改,并已实现。但不知道怎么实现,以下修改针对野火鲁班猫4的android-12。
com.kos.launcher是个用户级app,安装它后,不要让弹出权限申请窗口。
网上有这么篇文章“2022-08-25 AndroidR 默认赋予app权限,不弹出权限申请窗口”。那里提供了两条思路。
- 修改DefaultPermissionGrantPolicy.java中的grantDefaultSystemHandlerPermissions。试了下,没成功。grantDefaultSystemHandlerPermissions只能修改打包在android镜像的app权限(这结论是不是对,须要确认),而这里,com.kos.launcher是不打包在镜像,不满足这要求。
- 修改PackageManagerService.java中的handlePackagePostInstall。handlePackagePostInstall在安装app后、申请限权前执行,方法是在它调用mPermissionManager.grantRequestedRuntimePermissions,把这个app希望的权限都申请了。已经有了权限,后面app启动时检查权限,发现已赋予,自然不会申请,也就不会出现弹窗。但是,在android-12找不到grantRequestedRuntimePermissions这么个函数,这种方法也失败。
另一篇文章“android 权限成功回调 android权限检查”,说到当app启动时,发现缺少权限,会去调用requestPermissions()。
“requestPermissions主要是构建了一个action是“android.content.pm.action.REQUEST_PERMISSIONS”,package是PermissionController的intent,然后唤起相关界面。”
响应这个intent的是PermissionController apk,具体是com.android.packageinstaller.permission.ui.GrantPermissionsActivity。至此,GrantPermissionsActivity就是那个负责弹窗、处理用户选择、根据用户选择赋予权限的处理对象。
对如何解决本文提的要求,于是想到个方法,能不能一进去GrantPermissionsActivity,就赋予com.kos.launcher权限,然后就结束。这方法核心是找到GrantPermissionsActivity中赋予权限是哪个函数。
在权限选择界面,用户选择了某个选项后,会触发回调GrantPermissionsViewHandlerImpl.kt中的“fun onClick(view: View)”,这函数进而调用“resultListener!!.onPermissionGrantResult”,也就是GrantPermissionsActivity中的onPermissionGrantResult。
public class GrantPermissionsActivity extends SettingsActivity implements GrantPermissionsViewHandler.ResultListener { ... public void onPermissionGrantResult(String name, List<String> affectedForegroundPermissions, @GrantPermissionsViewHandler.Result int result) { if (checkKgm(name, affectedForegroundPermissions, result)) { return; } logGrantPermissionActivityButtons(name, affectedForegroundPermissions, result); mViewModel.onPermissionGrantResult(name, affectedForegroundPermissions, result); showNextRequest();
logGrantPermissionActivityButtons只是输出日志,对赋予操作没影响。
mViewModel.onPermissionGrantResult执行赋予操作。这是个同步操作,即只有该apk获得权限了,这函数才会返回。注意,onPermissionGrantResult是个*.kt中函数,不是java。
showNextRequest会显示下一个权限申请界面。它首先要关掉当前界面,如果还有未申请的,就显示下一个界面。它对赋予操作没影响。
if (result == CANCELED) { Log.e(LOG_TAG, "{leagor-install}onPermissionGrantResult, (3) call setResultAndFinish"); setResultAndFinish(); } } ... }
至此可以发现,只mViewModel.onPermissionGrantResult这么个么函数在执行着赋予权限操作。接下让看怎么填三个参数。
- name。权限分组AppPermissionGroup名。举个例子,相机权限是“android.permission-group.CAMERA”。
- affectedForegroundPermissions。和name有关的。像相机分组,这值是null。但对位置分组“android.permission-group.LOCATION”,是包含了“android.permission.ACCESS_FINE_LOCATION”和“android.permission.ACCESS_COARSE_LOCATION”的List<String>。
- result。用户做出的选择。“允许”对应GRANTED_ALWAYS(0),“仅在使用该应用时允许”对应GRANTED_FOREGROUND_ONLY(1),等等。
知道赋予权限函数、以及参数语义后,让修改onRequestInfoLoad函数,实现不弹窗、赋予com.kos.launcher权限。
private void onRequestInfoLoad(List<RequestInfo> requests) { ... } else if (requests.isEmpty()) { setResultAndFinish(); return; } // if (mCallingPackage.equals("com.kos.launcher")) { Log.i(LOG_TAG, "{leagor-install}onRequestInfoLoad, mCallingPackage: " + mCallingPackage + " my app"); String permissionGroupName; int grantResult = GRANTED_ALWAYS; // from GrantPermissionsViewHandler.GRANTED_ALWAYS permissionGroupName = "android.permission-group.CAMERA"; mViewModel.onPermissionGrantResult(permissionGroupName, null, grantResult); permissionGroupName = "android.permission-group.LOCATION"; List<String> affectedForegroundPermissions = new ArrayList<>(); affectedForegroundPermissions.add("android.permission.ACCESS_FINE_LOCATION"); affectedForegroundPermissions.add("android.permission.ACCESS_COARSE_LOCATION"); mViewModel.onPermissionGrantResult(permissionGroupName, affectedForegroundPermissions, grantResult); permissionGroupName = "android.permission-group.MICROPHONE"; mViewModel.onPermissionGrantResult(permissionGroupName, null, grantResult); permissionGroupName = "android.permission-group.NEARBY_DEVICES"; mViewModel.onPermissionGrantResult(permissionGroupName, null, grantResult); permissionGroupName = "android.permission-group.STORAGE"; mViewModel.onPermissionGrantResult(permissionGroupName, null, grantResult); setResultAndFinish(); return; }
修改方法就是在这里新增个if块。
if (mRequestInfos == null) { mTotalRequests = requests.size(); } mRequestInfos = requests; showNextRequest(); }
注意这个if块不能加在onCreate,像onCreate的return前执行,那会失败。至于com.kos.launcher权限须要哪些AppPermissionGroup,这可参考上面给的“android 权限成功回调 android权限检查”这篇文章。这里用了偷懒办法,因为只须要额外处理com.kos.launcher这个app,那让com.kos.launcher按弹出界面这个正常流程走一遍,然后记住调用多少次onPermissionGrantResult,以及每次填的是哪三个参数,依样写上就行。
在填写第三个参数result时,全部用了值GrantPermissionsViewHandler.GRANTED_ALWAYS(0)。虽然有分组在让选择时,最大是“仅在使用该应用时允许”GRANTED_FOREGROUND_ONLY(1),但换上更大范围GRANTED_ALWAYS,应该不会出错。
这方法有个缺陷,在知道缺少权限后(假设运行在线程a),它是通过向GrantPermissionsActivity发intent,GrantPermissionsActivity收到intent、以及处理,这须要时间。这期间,意味着线程a是没有该权限,这时可能会发生潜在争抢问题。如果能在启动com.kos.launcher时,就保证所有权限都获得了,像在handlePackagePostInstall就赋予权限,那自然会更好。