1.问题  

final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pInfo = packageManager.getInstalledPackages(0);

使用PackageManager工具获取所有安装包,但是在Android11及以上的手机中,部分应用比如微信com.tencent.mm,无法获取到。

2.原因-声明软件包可见性需求

Android 上的软件包可见性过滤

如果应用以 Android 11(API 级别 30)或更高版本为目标平台,并查询与设备上已安装的其他应用相关的信息,则系统在默认情况下会过滤此信息。从您的应用的角度来看,有限的软件包可见性会减少设备上显示的已安装应用数。

此过滤行为有助于最大限度减少显示您的应用在实现其用例时不需要的潜在敏感信息,但您的应用仍然可以访问这些信息。此外,过滤后的软件包可见性可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。例如,Google Play 会将已安装应用的列表视为个人和敏感用户数据。

有限的应用可见性会影响提供其他应用相关信息的方法的返回结果,例如 queryIntentActivities()、getPackageInfo() 和 getInstalledApplications()。有限的可见性还会影响与其他应用的显式交互,例如启动另一个应用的服务。

某些软件包仍然自动可见。您的应用始终可以在查询其他已安装的应用时看到这些软件包。如需查看其他软件包,请使用 <queries> 元素声明您的应用需要提高软件包可见性。用例页面提供了常见应用交互场景的示例。

在极少数情况下,如果遇到 <queries> 元素无法提供适当的软件包可见性,您还可以使用 QUERY_ALL_PACKAGES 权限。如果您在 Google Play 上发布应用,那么应用是否此权限需要根据即将生效的政策进行批准。

特定软件包名称

如果您知道要查询或与之交互的一组特定应用(例如,与您的应用集成的应用或您使用其服务的应用),请将其软件包名称添加到 <queries> 元素内的一组 <package> 元素中:

<manifest package="com.example.game">
    <queries>
        <package android:name="com.tencent.mm" />
        <package android:name="com.tencent.qq" />
        ...
    </queries>
</manifest>

注意:如果您在应用的清单中声明了 <package> 元素,则与该软件包名称关联的应用会出现在对 PackageManager 进行的任何与该应用的组件匹配的查询的结果中。

在库中与托管应用通信

如果您要开发 Android 库,您可以通过在 AAR 清单文件中添加 <queries> 元素来声明软件包可见性需求。此 <queries> 元素与应用可在自己的清单中声明的元素功能相同。

如果您的库涉及与“托管”应用通信(例如使用绑定服务),请添加用于指定托管应用的软件包名称的 <package> 元素:

<!-- Place inside the <queries> element. -->
<package android:name=PACKAGE_NAME />

通过添加此声明,您可以检查是否已安装托管应用并与之交互,例如通过调用 bindService() 来完成。此交互的结果是,使用您的库的调用方应用会自动对托管应用可见。

与 intent 过滤器签名匹配的软件包

您的应用可能需要查询一组具有特定用途的应用或与之交互,但您可能不知道要添加的具体软件包名称。在这种情况下,您可以在 <queries> 元素中列出 intent 过滤器签名。然后,您的应用就可以发现具有匹配的 <intent-filter> 元素的应用。

以下示例允许您的应用看到支持 JPEG 图片共享功能的已安装应用:

<manifest package="com.example.game">
    <queries>
        <intent>
            <action android:name="android.intent.action.SEND" />
            <data android:mimeType="image/jpeg" />
        </intent>
    </queries>
    ...
</manifest>

<intent> 元素有一些限制:

  • 您必须只添加一个 <action> 元素。
  • 您不能在 <data> 元素中使用 pathpathPrefixpathPattern 或 port 属性。系统的行为就像您将每个属性的值都设为通用通配符 (*) 一样。
  • 您不能使用 <data> 元素的 mimeGroup 属性。
  • 在单个 <intent> 元素的 <data> 元素中,您可以使用以下每个属性最多一次:
  • mimeType
  • scheme
  • host

您可以在多个 <data> 元素之间分配这些属性,也可以在单个 <data> 元素中使用这些属性。

<intent> 元素支持通用通配符 (*) 作为一些属性的值:

  • <action> 元素的 name 属性。
  • <data> 元素的 mimeType 属性的子类型 (image/*)。
  • <data> 元素的 mimeType 属性的类型和子类型 (*/*)。
  • <data> 元素的 scheme 属性。
  • <data> 元素的 host 属性。

除非前面列表中另有说明,否则系统不支持混合使用文本和通配符,如 prefix*

使用特定授权的软件包

如果您需要查询 Content Provider 但不知道具体的软件包名称,您可以在 <provider> 元素中声明该提供程序授权,如以下代码段所示:

<manifest package="com.example.suite.enterprise">
    <queries>
        <provider android:authorities="com.example.settings.files" />
    </queries>
    ...
</manifest>

注意:如果 <queries> 元素包含 <provider> 元素,您可能会在 Android Studio 中看到与 <provider> 元素相关的编辑器警告。只要您使用的是 Android Gradle 插件的最新“点”版本,您的 build 就不受影响,因此您可以忽略该警告。如需了解详情,请参阅有关为 Android 11 中的软件包可见性准备 Gradle build 的博文。

您可以在单个 <queries> 元素中声明所有提供程序授权。此格式取决于您声明提供程序授权的数量:

单个 <provider> 元素

        在元素中,声明以英文分号分隔的授权列表。

多个 <provider> 元素

        在每个元素中,声明单项授权或以英文分号分隔的授权列表。

所有应用(不推荐)

在极少数情况下,您的应用可能需要查询设备上的所有已安装应用或与之交互,不管这些应用包含哪些组件。为了允许您的应用看到其他所有已安装应用,系统会提供 QUERY_ALL_PACKAGES 权限。

下面列出了适合添加 QUERY_ALL_PACKAGES 权限的用例的一些示例:

  • 无障碍应用
  • 浏览器
  • 设备管理应用
  • 安全应用
  • 防病毒应用

不过,在绝大多数情况下,可以通过以下方式实现您应用的用例:与一组自动可见的应用交互,并在您的清单文件中声明您的应用需要访问的其他应用。为了尊重用户隐私,您的应用应请求应用正常工作所需的最小软件包可见性。

这项来自 Google Play 的政策更新为需要 QUERY_ALL_PACKAGES 权限的应用提供了相关准则。

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
    tools:ignore="QueryAllPackagesPermission" />