仅Android 6及以上三星设备抛出SecurityException问题求助
分析与解决方案:三星Android 6+设备调用
getLaunchIntentForPackage抛出SecurityException的问题 首先,从异常堆栈能定位到核心问题:这个SecurityException并不是直接来自getLaunchIntentForPackage本身,而是三星定制ROM在执行ApplicationPackageManager.getHiddenList时,调用Settings.Secure.getInt访问系统设置内容提供者时触发的权限校验失败。
为什么只有三星Android 6+设备会出现这个问题?
Android 6引入运行时权限后,三星在自家的TouchWiz/One UI ROM里对应用隐藏机制做了自定义强化:
- 原生Android的应用隐藏逻辑不会依赖
Settings.Secure的特定字段,但三星额外增加了通过系统设置存储隐藏应用列表的逻辑; - 当非系统应用调用PackageManager的相关查询方法(比如
getLaunchIntentForPackage、queryIntentActivities)时,三星的ROM会尝试访问这个自定义的系统设置内容提供者,而普通应用没有READ_SECURE_SETTINGS这个系统级权限,因此抛出SecurityException; - 不同三星机型的ROM版本(比如S5的Android 6 TouchWiz vs J7的高版本One UI)对权限校验的触发时机不同,导致你在S5加try-catch能解决,但J7的异常会在其他调用PackageManager的位置出现。
不依赖try-catch的解决方案
与其被动捕获异常,不如主动绕过三星的权限校验逻辑,以下是两种可行方案:
方案1:手动构造启动Intent,绕过原生getLaunchIntentForPackage
原生方法内部会触发三星的隐藏应用检查,我们可以直接查询该包名下的Launcher Activity,自己构造启动Intent:
public static Intent getSafeLaunchIntent(Context context, String packageName) { PackageManager pm = context.getPackageManager(); // 查询所有属于LAUNCHER类别的Activity Intent launcherIntent = new Intent(Intent.ACTION_MAIN); launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> resolveInfos = null; try { resolveInfos = pm.queryIntentActivities(launcherIntent, PackageManager.MATCH_ALL); } catch (SecurityException e) { // 兜底捕获,避免极端情况崩溃 e.printStackTrace(); } if (resolveInfos != null) { for (ResolveInfo info : resolveInfos) { if (info.activityInfo.packageName.equals(packageName)) { // 找到目标包的Launcher Activity,构造Intent Intent launchIntent = new Intent(Intent.ACTION_MAIN); launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); launchIntent.setComponent(new ComponentName( info.activityInfo.packageName, info.activityInfo.name )); launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return launchIntent; } } } // 如果没找到,再尝试原生方法(加兜底try-catch) try { return pm.getLaunchIntentForPackage(packageName); } catch (SecurityException e) { e.printStackTrace(); return null; } }
方案2:针对三星设备做特殊逻辑判断
可以先检测当前设备是否为三星,再针对性地使用不同的Intent获取逻辑:
public static boolean isSamsungDevice() { return "samsung".equalsIgnoreCase(Build.MANUFACTURER); } // 在调用时: Intent launchIntent; if (isSamsungDevice()) { launchIntent = getSafeLaunchIntent(context, packageName); } else { launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); }
补充说明
- 为什么S5加try-catch有效而J7不行?因为不同三星ROM的权限校验触发点不同:S5的异常只在
getLaunchIntentForPackage内部抛出,而J7的异常可能在queryIntentActivities等更早的步骤触发,所以只在一个地方加try-catch覆盖不全; READ_SECURE_SETTINGS权限是系统级权限,普通应用无法通过常规渠道获取,所以不要试图申请这个权限来解决问题。
内容的提问来源于stack exchange,提问作者Mohit Agrawal
相关产品推荐
相关产品推荐

