安装顺序错误时如何管理Android应用外部权限?
这个问题其实是Android自定义权限的典型安装顺序坑,我来给你拆解清楚并给出可行的解决方案:
为什么requestPermissions没效果?
首先要明确:你的自定义权限protectionLevel="normal",这类权限不需要运行时请求弹窗,系统只会在应用安装时自动授予——但前提是安装应用时,系统已经能识别到这个权限的定义(也就是MyService必须先安装,因为权限是在MyService的清单里声明的)。
如果先装MyLauncher,系统在安装它时找不到toto.myservice.WRITE_DATABASE的权限定义,就会默认拒绝这个权限请求。哪怕后来装了MyService,系统也不会自动更新MyLauncher的权限状态,而requestPermissions只对dangerous级别的权限生效,所以你调用后既不会弹框,权限也不会被授予。
不重装MyLauncher的解决方案
方案1:利用临时URI授权(最优解)
你的ContentProvider已经配置了android:grantUriPermissions="true",这意味着可以通过临时URI授权绕过静态权限的限制,具体步骤如下:
- 在MyService中提供一个触发授权的入口,比如通过BroadcastReceiver:
记得在MyService的清单里注册这个Receiver:// 示例:用BroadcastReceiver接收MyLauncher的授权请求 public class PermissionGrantReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String launcherPackage = intent.getStringExtra("launcher_package"); Uri contentUri = MyContentProvider.CONTENT_URI; // 替换成你的ContentProvider URI // 给MyLauncher授予临时写权限 context.getContentResolver().grantUriPermission( launcherPackage, contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); } }<receiver android:name=".PermissionGrantReceiver"> <intent-filter> <action android:name="toto.myservice.ACTION_REQUEST_PERMISSION"/> </intent-filter> </receiver> - 在MyLauncher中,每次需要写入数据前,先发送广播请求临时授权:
临时授权会在设备重启或MyLauncher进程被杀后失效,所以每次操作前请求一次即可,体验流畅且无需用户干预。Intent grantIntent = new Intent("toto.myservice.ACTION_REQUEST_PERMISSION"); grantIntent.putExtra("launcher_package", getPackageName()); sendBroadcast(grantIntent); // 等待授权完成后,再执行数据写入操作
方案2:引导用户手动刷新权限
如果不想做动态授权的开发,也可以引导用户手动触发系统刷新权限:
- 当MyLauncher检测到权限未授予时,弹出提示引导用户跳转到应用详情页:
if (ContextCompat.checkSelfPermission(this, "toto.myservice.WRITE_DATABASE") != PackageManager.PERMISSION_GRANTED) { new AlertDialog.Builder(this) .setTitle("权限需要更新") .setMessage("请在设置中开启数据库写入权限") .setPositiveButton("去设置", (dialog, which) -> { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); }) .show(); }
用户进入设置页后,系统会自动刷新权限列表,显示出你的自定义权限,用户手动开启后即可正常使用。这种方式需要用户操作,体验不如方案1,但开发成本低。
方案3:修改权限保护级别(不推荐)
如果把权限的protectionLevel改成dangerous,那么即使先装MyLauncher,后续装完MyService后调用requestPermissions会弹出授权弹窗。但这种方式会把普通权限升级为危险权限,增加用户的操作成本,不符合权限的原本定位,所以不推荐。
总结
如果不想让用户重装MyLauncher,临时URI授权是最优的解决方案,利用你已经配置的grantUriPermissions属性,就能完美解决安装顺序导致的权限问题。
内容的提问来源于stack exchange,提问作者Ludo




