在 Android 11(API 30)及更高版本中,调用 `PackageManager.getInstalledApplications()` 或 `getInstalledPackages()` 默认**仅返回当前应用自身及系统核心应用信息**,无法获取其他第三方应用列表。这是因 Google 引入了**包可见性(Package Visibility)限制**。开发者需在 `AndroidManifest.xml` 中显式声明 `` 元素,指明目标应用的包名、intent filter 或通用类别(如 `android.intent.category.BROWSABLE`)。例如,要查询所有已安装应用,需添加 ``(逐个声明)或使用 `` 等宽泛声明——但后者仍受 Play 商店政策与运行时行为约束。值得注意的是:**无需动态权限(如 QUERY_ALL_PACKAGES),但若需无差别访问全部应用(含未声明目标),必须在 `AndroidManifest.xml` 中声明 `android.permission.QUERY_ALL_PACKAGES`,且该权限为“特殊权限”,需经用户手动授予(Android 11+ 仅限特定用例,如杀毒、无障碍、设备管理类应用,普通应用极难通过 Google Play 审核)。** 常见误区是误以为 `INSTALL_PACKAGES` 或 `GET_TASKS` 仍有效——这些权限早已废弃或失效。
1条回答 默认 最新
冯宣 2026-02-27 04:31关注```html一、现象层:API 行为突变——为什么我的应用“看不见”其他 App?
从 Android 11(API 30)起,
PackageManager.getInstalledApplications(0)和getInstalledPackages(0)的返回结果急剧收缩:仅包含自身包、系统签名应用(如 Settings、SystemUI)、以及满足 包可见性(Package Visibility)策略 的第三方应用。这不是 Bug,而是 Google 强制推行的隐私沙箱核心机制之一。二、机制层:Package Visibility 的三重约束模型
- 静态声明优先:必须在
AndroidManifest.xml的<queries>根节点下显式声明目标应用能力 - 意图导向匹配:支持
<intent>子项(含action/category/data),例如可发现所有浏览器:<intent><action android:name="android.intent.action.VIEW"/><category android:name="android.intent.category.BROWSABLE"/></intent> - 包名白名单兜底:对已知关键依赖(如微信 SDK、支付宝 SDK),建议使用
<package android:name="com.tencent.mm"/>精确声明
三、权限层:QUERY_ALL_PACKAGES —— 特殊权限的“双刃剑”
维度 说明 声明方式 需在 AndroidManifest.xml中添加:<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>授予方式 非运行时动态请求;需用户进入「设置 → 应用 → 权限管理 → 查看所有应用」手动开启(Android 12+ UI 路径略有差异) Play 商店审核红线 仅允许设备管理类(Device Admin)、无障碍服务(AccessibilityService)、杀毒/安全类、家长控制、Launcher 类应用申请;普通工具/社交/电商类应用几乎 100% 拒绝上架 四、实践层:典型
<queries>声明模式对比<!-- 方案A:最小化声明(推荐)--> <queries> <package android:name="com.android.chrome"/> <package android:name="com.google.android.apps.nbu.files"/> <intent> <action android:name="android.intent.action.SEND"/> <data android:mimeType="text/plain"/> </intent> </queries> <!-- 方案B:宽泛但受限的声明(慎用)--> <queries> <intent> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.BROWSABLE"/> </intent> <intent> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent> </queries>五、误区澄清层:已被废弃/无效的旧权限与 API
android.permission.GET_TASKS:API 21+ 已废弃,返回空 TaskInfo 列表android.permission.INSTALL_PACKAGES:仅用于系统签名应用,普通应用调用PackageInstaller仍需用户确认界面,且无法绕过 Package VisibilityqueryIntentActivities()若未在<queries>中声明对应 intent,将返回空 List(即使目标 App 已安装)
六、架构层:适配 Package Visibility 的现代设计范式
graph LR A[调用 getInstalledPackages] --> B{是否需全量访问?} B -->|否| C[基于业务场景精简声明 ] B -->|是| D[评估是否符合 QUERY_ALL_PACKAGES 合规场景] D -->|是| E[申请权限 + 提交 Play 审核材料] D -->|否| F[重构方案:改用 Intent 分发/Deep Link 探测/WorkManager 周期性探测]七、兼容层:跨版本平滑过渡策略
建议采用
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R分支判断,并封装统一 PackageManager 封装器:- Android 10 及以下:直接调用
getInstalledPackages(0) - Android 11+:先尝试带
PackageManager.MATCH_VISIBLE_TO_INSTANT_APPS标志(已弃用),再 fallback 至getInstalledPackages(PackageManager.MATCH_DEFAULT_ONLY)+ 静态声明校验 - 对关键依赖包(如分享 SDK),强制在
<queries>中声明,避免运行时ActivityNotFoundException
八、审计层:自动化检测包可见性合规性的 CI/CD 实践
可在 Gradle 构建阶段集成 Lint 规则或自定义脚本扫描:
- 检查
AndroidManifest.xml是否缺失<queries>节点 - 验证所有
Intent.createChooser()中使用的 Action/Categories 是否已在<queries>中覆盖 - 比对 APK 中
AndroidManifest.xml与线上渠道 SDK 文档要求的包名白名单一致性
九、生态层:Google Play 政策与 OEM 定制行为差异
华为 HMS、小米 MIUI、OPPO ColorOS 等厂商在 Android 11+ 基础上进一步收紧可见性逻辑:
- 部分国产 ROM 对
<queries>中<intent>的dataschema 匹配更严格(如要求完整 host/path) - 华为 AppGallery 要求提交
QUERY_ALL_PACKAGES使用场景说明文档,并进行人工复审 - 三星 One UI 12+ 引入“后台应用探测限制”,即使声明了
<package>,若目标 App 处于冻结状态,仍可能返回 null
十、演进层:Android 14(API 34)新增约束与前瞻
Android 14 引入
android:exported="true"默认规则强化及QUERY_ALL_PACKAGES运行时二次确认弹窗:- 所有
<activity>/<service>若含 intent-filter,必须显式声明android:exported - 调用
getInstalledPackages(PackageManager.MATCH_ALL)时,系统会触发额外权限确认对话框(即使 manifest 已声明) - Google 正推动
AppSearch和ShortcutManager替代传统包枚举,建议长期规划迁移路径
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- 静态声明优先:必须在