如何修复Intent.ACTION_PICK_ACTIVITY引发的java.lang.SecurityException错误?
我之前处理华为旧机型兼容问题时碰到过一模一样的情况,给你拆解下问题根源和可行的修复方案:
Fatal Exception: java.lang.SecurityException Permission Denial: starting Intent { act=android.intent.action.PICK_ACTIVITY cmp=com.android.settings/.ActivityPicker (has extras) } from ProcessRecord{41bc95c0 6397:com.sampleapp.sample/u0a10087} (pid=6397, uid=10087) requires android.permission.SECURITY_ACTIVITY
这个异常的核心原因是:华为在Android 4.2.2和4.4.2的定制系统里,给Intent.ACTION_PICK_ACTIVITY这个动作加了系统签名级的自定义权限——android.permission.SECURITY_ACTIVITY。普通第三方APP根本没法申请这个权限(只有系统自带应用或者拥有系统签名的APP才能使用),所以直接调用就会触发权限拒绝。
最简便的修复:改用系统标准分享选择器
放弃用ACTION_PICK_ACTIVITY构建选择器,直接用Android官方推荐的Intent.createChooser()方法,这是所有设备都兼容的标准方案,完全不会碰到权限问题。
修改后的代码如下:
Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.setType("text/plain"); sendIntent.putExtra(Intent.EXTRA_TEXT, "Text to share"); // 用系统选择器替代原来的ACTION_PICK_ACTIVITY Intent chooserIntent = Intent.createChooser(sendIntent, "Share link"); this.startActivityForResult(chooserIntent, REQUEST_CODE_MY_PICK);
这个方案不仅能解决权限问题,还完整保留了你原来的需求:
- 第二个参数
"Share link"就是选择器的标题,和你之前设置的Intent.EXTRA_TITLE效果完全一致 - 系统选择器的UI和交互都是用户熟悉的样式,体验更统一
如果需要定制化选择器怎么办?
要是你需要过滤特定应用、自定义选择器UI,那可以自己手动获取支持分享的应用列表,然后构建自定义界面:
PackageManager pm = getPackageManager(); // 获取所有支持ACTION_SEND的应用 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(sendIntent, 0); // 这里可以遍历resolveInfos,提取每个应用的名称、图标、组件信息 // 然后用RecyclerView或者ListView做一个自定义选择列表 // 用户选择后,直接构建对应的Intent启动即可 Intent targetIntent = new Intent(sendIntent); targetIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)); startActivityForResult(targetIntent, REQUEST_CODE_MY_PICK);
这种方式完全避开了系统的ACTION_PICK_ACTIVITY,也就不会触发华为的权限限制,同时能实现你想要的定制化效果。
内容的提问来源于stack exchange,提问作者kev

