管理软件包可见性

在创建应用时,请务必考虑您的应用打算访问的一组软件包,这些软件包代表设备上的其他已安装应用。如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,在默认情况下,系统会自动让部分应用对您的应用可见,但会隐藏其他应用。通过让部分应用在默认情况下不可见,系统可以了解应向您的应用显示哪些其他应用,这样有助于鼓励最小权限原则,还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。

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

本指南列出了一组自动对您的应用可见的应用,并介绍了如何让其他应用对您的应用可见。此外,本指南还针对如何配置日志消息以确定其他应用的可见性对您的应用有何影响提供了一些建议。

自动可见的应用

系统会自动让部分应用对您的应用可见,以便您的应用可与其交互,而无需声明 <queries> 元素。此行为有助于支持基本功能和常见用例。

尤其要注意,即使您的应用以 Android 11(API 级别 30)或更高版本为目标平台,以下类型的应用也始终对您的应用可见:

  • 您自己的应用。
  • 实现 Android 核心功能的某些系统软件包,如媒体提供程序。详细了解如何在运行您应用的设备上确定自动显示哪些软件包
  • 安装了您应用的应用。
  • 使用 startActivityForResult() 方法在您的应用中启动 activity 的任何应用,正如如何获取 activity 的结果这一指南中所述。
  • 启动或绑定到您应用中的某项服务的任何应用。
  • 访问您应用中的 Content Provider 的任何应用。
  • 具有 Content Provider 的任何应用,其中您的应用已被授予 URI 权限来访问该 Content Provider。
  • 接收您应用的输入的任何应用。这种情况仅适用于您的应用作为输入法应用提供输入。

此外,您可以使用隐式显式 intent 来启动另一应用的 activity,无论这个应用是否对您的应用可见。

自动可见的系统软件包

实现 Android 核心功能的某些系统软件包会自动对您的应用可见,即使您的应用以 Android 11(API 级别 30)或更高版本为目标平台也是如此。这组特定的软件包取决于运行您应用的设备。

如需查看特定设备的完整软件包列表,请在开发机器上的终端中运行以下命令:

adb shell dumpsys package queries

在命令输出中,找到 forceQueryable 部分。本部分包含设备上自动对您的应用可见的软件包列表。

声明您的应用与一组特定的其他应用交互

如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,并且需要与应用(自动可见的应用除外)交互,请在您应用的清单文件中添加 <queries> 元素。在 <queries> 元素中,按软件包名称按 intent 签名按提供程序授权指定其他应用,如以下部分所述。

查询特定软件包及与之交互

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

<manifest package="com.example.game">
    <queries>
        <package android:name="com.example.store" />
        <package android:name="com.example.services" />
    </queries>
    ...
</manifest>

在给定 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> 元素中使用 pathpathPrefixpathPatternport 属性。系统的行为就像您将每个属性的值都设为通用通配符 (*) 一样。
  • 您不能使用 <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> 元素中,声明以英文分号分隔的授权列表。
  • 添加多个 <provider> 元素,让这些元素全部在同一 <queries> 元素中。在每个 <provider> 元素中,声明单项授权或以英文分号分隔的授权列表。

查询所有应用及与之交互

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

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

  • 启动器应用
  • 无障碍应用
  • 浏览器
  • 点对点 (P2P) 共享应用
  • 设备管理应用
  • 安全应用

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

在即将发布的政策更新中,Google Play 会为需要 QUERY_ALL_PACKAGES 权限的应用提供相关指南,敬请期待。

软件包过滤的日志消息

如需详细了解应用的默认可见性对您的应用有何影响,您可以启用软件包过滤的日志消息。如果您是在 Android Studio 中开发测试应用或可调试应用,系统会为您启用该功能。或者,您也可以在终端窗口中运行以下命令,手动启用该功能:

adb shell pm log-visibility --enable PACKAGE_NAME

然后,每当从 PackageManager 对象的返回值中滤除软件包时,您都会在 Logcat 中看到类似于以下内容的消息:

I/AppsFilter: interaction: PackageSetting{7654321 \
  com.example.myapp/12345} -> PackageSetting{...} BLOCKED