行为变更 | Android 12 中不受信任的触摸事件

行为变更 | Android 12 中不受信任的触摸事件

我们在 Android 12 中进行了一些变更,来提升应用和平台的安全性,进而使我们的用户能够拥有更安全的使用体验。回顾关于隐私和安全的文章,请参阅: 政策更新 | 开发者如何处理软件包可见性

触摸控制是 Android 系统中同应用进行交互的主要方式。Android 12 中采取了额外的措施,来确保触摸事件被正确地传递给了应该响应此事件的应用,以此确保触摸交互的直观和安全性。具体地说,就是在 Android 12 中,如果触摸事件是从一个不同的应用窗口传递的,那么此事件会被屏蔽。这一改变将影响所有在 Android 12 中运行的应用,且与应用的 "targetSdkVersion" 无关。这有助于帮助用户更直观地确认他们正在进行交互的应用。继续阅读本文来看看您的应用是否会受到此变更的影响,以及了解如何针对此变更测试您的应用。

尽可能使用特殊用途 (Special-Purpose) 的 API

在检查您的应用是否会受此影响之前,最好先评估一下您应用的某些场景是否可以使用以下 Android API。这些 API 部分由系统控制,可以被信任,因此您不需要担心使用这些 API 会受到限制。它们是:

  • Bubbles: Bubbles 是像气泡一样浮动在其他应用内容的上层,并且会跟随用户所处的位置,还可以展开以显示应用功能和信息。
  • Picture-in-Picture (PIP): PIP 功能允许应用在一个小窗口中显示内容,用户可以通过固定到屏幕一角的小窗口观看视频,同时在应用之间进行导航或浏览主屏幕上的内容。用户还可以拖动 PIP 窗口,并可以点击它来展开或进行关闭。
  • Notifications: 通知是指 Android 在您应用的界面之外显示的消息,旨在向用户提供提醒、来自他人的通信信息或您应用中的其他适时弹出的信息。用户可以点按通知来打开应用,或直接在通知中执行操作。
  • SnackbarsToasts: 如果您需要在应用中显示一条简短的信息,可以使用 Snackbars。如果您需要应用在后台的情况下显示信息,可以看看 Toasts 是否符合您的需求。

如果您应用的使用场景匹配了上述某个 API 的使用场景,那么强烈建议您使用这些 API。不仅仅是因为这些 API 简单易用,它们还更加安全,而且用户已经对它们中的大多数很熟悉了。

我会受到影响吗?

如果您的应用不能使用上述 API,而是让触摸事件直接通过其窗口传递,那么在 Android 12 中它们可能无法按预期传递到下层。这方面的例子包括但不仅限于以下示例:

如果您正在使用 FLAG_NOT_TOUCHABLE,那么您的应用可能会被影响,除非您的应用符合以下某个豁免条件:

如果您的使用场景并不包含于上述列表内,那么触摸事件将会被屏蔽。否则的话,如果您想阻止触摸事件传递,可以考虑删除 FLAG_NOT_TOUCHABLE 标志,而如果想让触摸事件穿透下去,可以调整您的代码来符合上述的几种情况之一。接下来我们会介绍必须要改变的一些常见模式的例子。

有着透明背景且无 UI 元素的窗口

在有着透明背景的窗口中展示某些 UI 的应用,可以在适当的时候在视图层面隐藏它们的 UI,同时添加 FLAG_NOT_TOUCHABLE 标志,这样用户就可以与下层的内容进行交互了。

如果像上图一样,应用仅仅是隐藏了 UI,要么是通过删除子视图的方法隐藏,或是改变它们的可见性 (visibility) 并添加 FLAG_NOT_TOUCHABLE 标志来允许用户与下层的视图进行交互,因为对下层其他应用的触摸事件会被屏蔽,所以这样的方法在 Android 12 上就不再起作用了 (注意与前面提到的豁免条件的区别,在这里我们改变的是内部视图,而不是窗口)。在这种情况下想解决此类问题,您可以:

每当您需要再次显示那个界面时,您只需要把上面的动作反过来设置即可。

不必要的大窗口

有时应用会想要显示一些小的 UI 界面,并同时允许用户同窗口下层的内容进行交互。在之前,应用可以通过简单地使用一个全屏窗口,并将其标记为 FLAG_NOT_TOUCHABLE 来实现,如图 1 所示:

请注意,在以前的操作系统版本中,通过实际的 UI 元素进行的触摸事件,在这种情况下会传递到下层的窗口中。在这种情况下,首先请查看一下 Toast API 是否能满足需求,不行的话,解决方案也很简单——在右侧的图片有说明: 您只需要将窗口的边界缩小到实际的 UI 大小,并使用 FLAG_NOT_TOUCH_MODAL,有时您也可能需要删除 FLAG_NOT_TOUCHABLE

这样,在您的 UI 外的触摸事件,将直接穿透到下层的窗口,不再被屏蔽。

半透明窗口

如果您使用了一个 TYPE_APPLICATION_OVERLAY 窗口,并需要在显示内容时允许触摸事件穿透下去,那您就必须降低窗口的不透明度,让用户能够合理地看到他们在窗口后所触摸的 UI 元素。

您必须在 窗口级别 上降低不透明度,仅仅改变视图的不透明度是不行的。您可以使用 LayoutParams.alpha 来降低不透明度,使其低于或者等于
InputManager.getMaximumObscuringOpacityForTouch() 的值,如右边的图片所示。这个值目前是 0.8,但是在 Android 12 最终版本发布前可能会改变。

现在,只要您应用内的多个窗口没有相互重叠,触摸事件就会穿透到下层的窗口。关于重叠窗口的更多细节,请查阅 FLAG_NOT_TOUCHABLE 文档。

无障碍服务

当使用 AccessibilityService (无障碍服务) 时,它可以创建 TYPE_ACCESSIBILITY_OVERLAY 类型的窗口,这些窗口是可信任的,因此可以免于前面所描述的一些限制。您只需要结合 AccessibilityService 的上下文,通过 getSystemService() 方法获得一个 WindowManager 来创建上述窗口。

如何测试您的应用是否受到影响

如果系统屏蔽了触摸操作,Logcat 会输出以下信息:

Untrusted touch due to occlusion by PACKAGE_NAME.

接下来

如果您想了解到更多关于不受信任的触摸事件以及它们的例外情况,请查阅相关文档:

版权声明

禁止一切形式的转载-禁止商用-禁止衍生 申请授权

脉脉不得语
脉脉不得语
Zhengzhou Website
Android Developer | https://androiddevtools.cn and https://androidweekly.io WebMaster | GDG Zhengzhou Funder & Ex Organizer | http://Toast.show(∞) Podcast Host

你已经成功订阅到 Android 开发技术周报
太棒了!接下来,完成检验以获得全部访问权限 Android 开发技术周报
欢迎回来!你已经成功登录了。
Unable to sign you in. Please try again.
成功!您的帐户已完全激活,您现在可以访问所有内容。
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.