You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

安装顺序错误时如何管理Android应用外部权限?

问题分析与解决方案

这个问题其实是Android自定义权限的典型安装顺序坑,我来给你拆解清楚并给出可行的解决方案:

为什么requestPermissions没效果?

首先要明确:你的自定义权限protectionLevel="normal",这类权限不需要运行时请求弹窗,系统只会在应用安装时自动授予——但前提是安装应用时,系统已经能识别到这个权限的定义(也就是MyService必须先安装,因为权限是在MyService的清单里声明的)。

如果先装MyLauncher,系统在安装它时找不到toto.myservice.WRITE_DATABASE的权限定义,就会默认拒绝这个权限请求。哪怕后来装了MyService,系统也不会自动更新MyLauncher的权限状态,而requestPermissions只对dangerous级别的权限生效,所以你调用后既不会弹框,权限也不会被授予。

不重装MyLauncher的解决方案

方案1:利用临时URI授权(最优解)

你的ContentProvider已经配置了android:grantUriPermissions="true",这意味着可以通过临时URI授权绕过静态权限的限制,具体步骤如下:

  1. 在MyService中提供一个触发授权的入口,比如通过BroadcastReceiver:
    // 示例:用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
            );
        }
    }
    
    记得在MyService的清单里注册这个Receiver:
    <receiver android:name=".PermissionGrantReceiver">
        <intent-filter>
            <action android:name="toto.myservice.ACTION_REQUEST_PERMISSION"/>
        </intent-filter>
    </receiver>
    
  2. 在MyLauncher中,每次需要写入数据前,先发送广播请求临时授权:
    Intent grantIntent = new Intent("toto.myservice.ACTION_REQUEST_PERMISSION");
    grantIntent.putExtra("launcher_package", getPackageName());
    sendBroadcast(grantIntent);
    // 等待授权完成后,再执行数据写入操作
    
    临时授权会在设备重启或MyLauncher进程被杀后失效,所以每次操作前请求一次即可,体验流畅且无需用户干预。

方案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

火山引擎 最新活动