Android开发:如何判断应用是否为系统应用或平台密钥签名应用
编译报错原因
你看到的两个常量虽然被
public static修饰,但都带了@hide注解,属于Android系统的隐藏API,官方提供的公开SDK编译包中已经移除了这两个符号的声明,因此常规开发环境下无法直接引用,才会报未找到引用的错误。
替代解决方案
方案1:判断应用是否可直接卸载(适配Launcher场景)
如果你核心需求是给用户展示正确的卸载入口,优先用这个方案,不需要单独区分系统应用/平台签名应用:
/** * @return 应用是否支持用户完全卸载 */ public boolean isAppUninstallable(Context context, String packageName) { try { PackageManager pm = context.getPackageManager(); ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0); // 非系统应用均可卸载 if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return true; } // 被用户更新过的系统应用可卸载更新,不支持完全卸载,按需调整返回值 return (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; } }
如果返回true才展示卸载选项即可。
方案2:校验应用是否使用平台密钥签名
如果你试过FLAG_SYSTEM、FLAG_UPDATED_SYSTEM_APP不符合过滤需求,需要单独过滤平台签名应用,可以用签名匹配的方式实现,不需要调用隐藏API:
/** * @return 应用是否使用系统平台密钥签名 */ public boolean isAppSignedWithPlatformKey(Context context, String packageName) { try { PackageManager pm = context.getPackageManager(); Signature[] appSigs; // 读取目标应用签名 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES); appSigs = pkgInfo.signingInfo.getApkContentsSigners(); } else { PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); appSigs = pkgInfo.signatures; } // 读取系统平台签名(android包是系统核心框架,用平台密钥签名) Signature[] platformSigs = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES).signatures; // 匹配签名 for (Signature appSig : appSigs) { for (Signature platformSig : platformSigs) { if (appSig.equals(platformSig)) { return true; } } } return false; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; } }
把返回true的应用加入不可卸载列表即可。
方案3:强制使用隐藏API(不推荐,兼容性差)
如果一定要调用你找到的这两个私有标志,可以用两种方式绕过编译限制:
- 硬编码常量值:直接用
1 << 20代替PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY,1 << 21代替PRIVATE_FLAG_SYSTEM_EXT,和ActivityInfo.privateFlags做与运算判断。注意不同Android版本的隐藏常量值可能调整,兼容性没有保障。 - 反射读取:运行时反射读取
ActivityInfo类的对应字段值,再做位运算判断。
内容的提问来源于stack exchange,提问作者Draško
相关产品推荐
相关产品推荐

