Android 11 中的软件包可见性
Android 11 更改了应用查询用户已在设备上安装的其他应用以及与之交互的方式。使用新的 元素,应用可以定义一组自身可访问的其他应用。通过告知系统应向您的应用显示哪些其他应用,此元素有助于鼓励最小权限原则。此外,此元素还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。
如果应用以 Android 11 为目标平台,您可能需要在应用的清单文件中添加 元素。在 元素中,您可以按软件包名称或按 intent 签名指定应用。
注意:在某些情况下,即使您的应用以 Android 11 为目标平台,您也根本不需要更新自己的应用来支持这一变更。
返回其他应用相关结果的方法(如)会根据发起调用的应用的声明进行过滤。与其他应用的显式交互(如)还要求目标应用与中的某项声明相符。
设置您的环境
如需构建使用 元素的应用,请使用以下工具:
- Android Studio 3.6.1 或更高版本
- 最新版本的 Android Gradle 插件
查询特定软件包及与之交互
如果您知道要查询或与之交互的一组特定应用(例如,与您的应用集成的应用或您使用其服务的应用),请将其软件包名称添加到 元素内的一组 元素中:
<manifest package=”com.example.game”>
<queries>
<package android_name=”com.example.store” />
<package android_name=”com.example.services” />
</queries>
…
</manifest>
在给定 intent 过滤器的情况下查询应用及与之交互
您的应用可能需要查询一组具有特定用途的应用或与之交互,但您可能不知道要添加的具体软件包名称。在这种情况下,您可以在 元素中列出 intent 过滤器签名。然后,您的应用就可以发现具有匹配的 元素的应用。
以下示例允许您的应用看到支持 JPEG 图片共享功能的已安装应用:
<manifest package=”com.example.game”>
<queries>
<intent>
<action android_name=”android.intent.action.SEND” />
<data android_mimeType=”image/jpeg” />
</intent>
</queries>
…
</manifest>
元素有一些限制:
- 您必须只添加一个 元素。
- 您不能在 元素中使用 、、 或 属性。系统的行为就像您将每个属性的值都设为通用通配符 () 一样。
- 您不能使用 元素的 属性。
- 在单个 元素的 元素中,您可以使用以下每个属性最多一次:
您可以在多个 元素之间分配这些属性,也可以在单个 元素中使用这些属性。
元素支持通用通配符 () 作为一些属性的值:
- 元素的 属性。
- 元素的 属性的子类型 ()。
- 元素的 属性的类型和子类型 ()。
- 元素的 属性。
- 元素的 属性。
除非前面列表中另有说明,否则系统不支持混合使用文本和通配符,如 。
查询所有应用及与之交互
在极少数情况下,您的应用可能需要查询设备上的所有已安装应用或与之交互,不管这些应用包含哪些组件。为了允许您的应用看到其他所有已安装应用,Android 11 引入了 权限。
下面列出了适合添加 权限的用例的一些示例:
- 启动器应用
- 无障碍应用
- 浏览器
- 点对点 (P2P) 共享应用
- 设备管理应用
- 安全应用
不过,在绝大多数情况下,可以通过声明 元素实现应用的用例。为了尊重用户隐私,您的应用应请求应用正常工作所需的最小软件包可见性。
在即将发布的政策更新中,Google Play 会为需要 权限的应用提供相关指南,敬请期待。
软件包过滤的日志消息
如需详细了解软件包可见性的变更对您的应用有何影响,您可以启用软件包过滤的日志消息。如果您是在 Android Studio 中开发测试应用或可调试应用,系统会为您启用该功能。或者,您也可以在终端窗口中运行以下命令,手动启用该功能:
adb shell pm log-visibility –enable PACKAGE_NAME
然后,每当从对象的返回值中滤除软件包时,您都会在 Logcat 中看到类似于以下内容的消息:
I/AppsFilter: interaction: PackageSetting{7654321
com.example.myapp/12345} -> PackageSetting{…} BLOCKED
测试变更
如需测试此行为变更是否已在您的应用中生效,请完成以下步骤:
- 安装 Android Studio 3.6.1 或更高版本。
- 安装 Android Studio 支持的最新版 Gradle。
- 将应用的 设为 。
- 不要在应用的清单文件中添加 元素。
- 调用 或 。这两种方法都应返回过滤后的列表。
- 查看应用的哪些功能无法正常使用。
- 引入适当的 条目来修复这些功能。
不受变更影响的用例
以下列表包含几个不需要 声明的用例示例:
- 目标应用是您自己的应用。
- 您可以使用隐式 intent 启动 Activity。您的应用可能会限制其使用隐式 intent 与其他应用交互的方式。
- 您的应用与实现 Android 核心功能的某些系统软件包(如媒体提供程序)交互。
- 其他应用期望从您的应用获得结果。当您的应用是内容提供程序时、当其他应用通过调用 调用您的应用时,以及当您的应用是其他应用尝试启动或连接到的服务时,会出现这种情况。
例如,如果其他应用向您应用中的内容提供程序发出请求,系统将允许您的应用看到该其他应用。
为 Activity 开始时间添加限制
Android 11 增加了多个标记,可让您指定何时从应用调用 应产生,而不是让其他应用处理 intent。通过使用这些标记,您无需调用 或 。
这些标记对于 络 intent 特别有用。当您的应用希望深层链接到已安装的应用且该应用无法访问时,您的应用可以通过在自定义标签页或应用内浏览器中加载 址自行处理 intent。
在非浏览器应用中启动 络 intent
如果您添加了 intent 标记,只有在以下情况下才会启动 intent:
- 非浏览器应用会直接处理 intent。
- 用户可以在消除歧义对话框中选择非浏览器应用。
否则,系统将抛出 ,并且您的应用应自行处理 intent。
仅需一个匹配 Activity
如果您添加了 intent 标记,当设备上只有一个应用可以处理您应用的 intent 时,或者当某个应用是该 intent 的默认处理程序时,会调用您应用的 intent。此标记不会显示消除歧义对话框,而是允许应用选择如何向用户显示内容,从而省去一些麻烦。
- 依赖库或 SDK 中的代码访问私密数据。
注意:如果您的应用在多个组件(例如在前台服务和后台任务)中访问数据,请创建自定义子类,并在子类的方法中定义。
在特定情况下,需要调用 和 方法:
- 如果数据访问并非发生在应用调用 API 期间,需要调用 。最常见的一个例子就是,在您的应用注册了监听器后,每次调用该监听器的回调时都会发生数据访问。
传递到 中的 参数包含名为 的方法。此方法提供了有关数据访问的详细信息。如果是位置信息回调,该消息将包含监听器的系统身份哈希值。 - 在极少数情况下,如果应用将自身的 UID 传递到 ,需要调用 。
如需在应用中定义归因标记,请完成以下部分中的步骤。
创建归因标记
如果您在某个 Activity 中访问数据(例如请求位置信息或访问用户的联系人列表),请在该 Activity 的 方法中调用 ,并传入您希望与应用的一部分相关联的归因标记。
以下代码段展示了如何为应用的“照片位置信息分享”部分创建归因标记:
在访问日志中包含归因标记
更新您的 回调,以将您定义的归因标记的名称包含于应用的日志中。
注意:如果归因标记的返回值为,意味着当前的对象与您应用的主要部分相关联。
以下代码段展示了记录归因代码的更新逻辑:
@Override
public void onCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState) {
AppOpsManager.OnOpNotedCallback appOpsCallback =
new AppOpsManager.OnOpNotedCallback() {
private void logPrivateDataAccess(String opCode,
String attributionTag, String trace) {
Log.i(“MY_APP_TAG”, “Private data accessed. ” +
“Operation: $opCoden ” +
“Attribution Tag:$attributionTagnStack Trace:n$trace”);
}
@Override
public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
logPrivateDataAccess(syncNotedAppOp.getOp(),
syncNotedAppOp.getAttributionTag(),
Arrays.toString(new Throwable().getStackTrace()));
}
@Override
public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
logPrivateDataAccess(syncNotedAppOp.getOp(),
syncNotedAppOp.getAttributionTag(),
Arrays.toString(new Throwable().getStackTrace()));
}
@Override
public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) {
logPrivateDataAccess(asyncNotedAppOp.getOp(),
asyncNotedAppOp.getAttributionTag(),
asyncNotedAppOp.getMessage());
}
};
AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
if (appOpsManager != null) {
appOpsManager.setNotedAppOpsCollector(appOpsCollector);
}
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!