You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级compileSdkVersion、targetSdkVersion至30后无法检测应用是否已安装

targetSdkVersion 30 以上应用安装判断的适配方案

报错根因

Android 11(API 30)正式上线包可见性权限机制,对应用可获取的其他应用信息做了强限制:

  • 当targetSdkVersion >= 30时,应用默认看不到设备上绝大多数第三方应用的包信息
  • 直接调用getPackageInfo()查询未声明的目标包名时,系统会直接抛出PackageManager.NameNotFoundException,不会返回null
  • 这也是为什么targetSdkVersion为29时代码运行正常,升级到30就报错的核心原因

具体适配操作

1. 清单文件声明包可见范围(必须)

在AndroidManifest.xml的<manifest>标签下添加<queries>节点,显式声明需要查询的目标应用包名,告知系统需要开放对应的包信息访问权限:

<manifest>
    <!-- 按需列出所有需要判断安装状态的应用包名 -->
    <queries>
        <!-- Facebook 正式版包名 -->
        <package android:name="com.facebook.katana" />
        <!-- Twitter 正式版包名 -->
        <package android:name="com.twitter.android" />
    </queries>

    <application>
        ...
    </application>
</manifest>

注意:如果没有合理的业务场景,不要直接申请android.permission.QUERY_ALL_PACKAGES全量查询权限,该权限会被Google Play及国内主流应用市场严格审核,非必要场景提交会被直接驳回。

2. 代码增加异常捕获做容错

getPackageInfo()方法在查询不到目标包时会直接抛出异常,不会返回null,需要用try-catch包裹调用逻辑,避免应用崩溃。修改后的参考代码如下:

String packageName = "com.facebook.katana";
PackageInfo installInfo = null;
try {
    installInfo = context.getPackageManager().getPackageInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
    // 捕获异常说明目标应用未安装,直接走未安装分支
    LogTool.c(TAG, "Target app " + packageName + " is not installed");
}

if (installInfo != null && installInfo.applicationInfo.enabled) {
    LogTool.c(TAG, platform.name() + " is installed");
    return true;
}
return false;

常见踩坑提醒

  • 原有代码中对包信息对象的判空逻辑,在API 30+版本下对getPackageInfo调用是冗余的:未查询到包时会直接触发异常,不会走到返回null的分支
  • 如果目标应用是工作资料、多开分身下的应用,就算声明了<queries>也可能存在查询不到的场景,需要结合实际业务做单独适配
  • 如果是需要通过意图判断应用是否可响应的场景,除了包名声明,也可以在<queries>下通过<intent>节点声明需要匹配的意图过滤器,适配性会更好

内容的提问来源于stack exchange,提问作者DavidR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.24 19:45:07