欢迎使用 Android 12 开发者预览版!请尽早并且经常向我们提供反馈,帮助我们将 Android 12 打造为最佳版本!

行为变更:以 Android 12 为目标平台的应用

与早期版本一样,Android 12 包含一些行为变更,这些变更可能会影响您的应用。以下行为变更仅影响以 Android 12 或更高版本为目标平台的应用。如果您的应用以 Android 12 为目标平台,您应该修改自己的应用以适当地支持这些行为(如果适用)。

下表总结了影响以 Android 12 为目标平台的应用的重要变更。请注意,此表并不包含全部变更。

重要变更 受影响的应用
前台服务启动限制
除少数例外情况,应用再也无法在后台运行时启动前台服务。否则,系统会抛出异常。
在后台运行时启动前台服务的应用。
包含 intent 过滤器的应用组件必须声明导出的属性
包含 intent 过滤器的应用组件必须显式设置 android:exported 属性。 未设置该属性的应用无法安装在 Android 12 上。
在清单文件中声明 <intent-filter> 属性的应用。
以不安全的方式启动嵌套 intent
严格模式测试现在会检测您的应用何时以不安全的方式使用嵌套 intent。
启动另一个应用并期望通过内部 intent 回调的应用。

此外,请务必查看对 Android 12 上运行的所有应用都有影响的行为变更列表。

隐私设置

WebView 中的现代 SameSite Cookie 行为

Android 的 WebView 组件基于为 Google 的 Chrome 浏览器提供支持的开源项目 Chromium。在过去一年中,Chromium 变更了对第三方 Cookie 的处理方式,目的是为了更好地保护用户的安全和隐私,并赋予用户更高的透明度和控制权。这些变更已面向很多 Chrome 用户发布,从 Android 12 开始,这些变更将应用于 WebView 中。

Cookie 的 SameSite 属性决定了它是可以与任何请求一起发送,还是只能与同站点请求一起发送。Android 12 中的 WebView 基础版本(版本 89.0.4385.0)包含以下隐私保护方面的变更,旨在改善对第三方 Cookie 的默认处理方式,并帮助防止意外跨站点共享:

  • 没有 SameSite 属性的 Cookie 被视为 SameSite=Lax
  • 带有 SameSite=None 的 Cookie 还必须指定 Secure 属性,这意味着它们需要安全的上下文,并应通过 HTTPS 发送。
  • 站点的 HTTP 版本和 HTTPS 版本之间的链接现在被视为跨站点请求,因此除非将 Cookie 正确标记为 SameSite=None; Secure,否则 Cookie 不会被发送。

对于开发者而言,一般指导意见是识别关键用户流中的跨站点 Cookie 依赖项,并确保在需要时使用适当的值显式设置 SameSite 属性。您必须显式指定允许在不同网站上运行的 Cookie,或适用于从 HTTP 切换到 HTTPS 进行同站点导航的 Cookie。

如需了解有关这些变更的网站开发者完整指南,请参阅 SameSite Cookie 说明Schemeful SameSite

在您的应用中测试 SameSite 行为

如果您的应用使用 WebView,或者您需要管理使用 Cookie 的网站或服务,我们建议您在 Android 12 WebView 上测试您的数据流。 如果发现问题,您可能需要更新 Cookie 以支持新的 SameSite 行为。

留意登录和嵌入式内容中存在的问题,以及用户从不安全的页面启动并转到安全页面的登录流、购买和其他身份验证流。

如需使用 WebView 测试应用,您必须完成以下任一步骤,为需要测试的应用启用新的 SameSite 行为:

  • WebView devtools切换界面标志 webview-enable-modern-cookie-same-site,在测试设备上手动启用 SameSite 行为。

    此方法允许您在任何运行 Android 5.0(API 级别 21)或更高版本(包括 Android 12)和 WebView 版本 89.0.4385.0 或更高版本的设备上进行测试。

  • 通过 targetSdkVersion 编译您的应用,使其以 Android 12 为目标平台。

    如果您使用此方法,则必须使用运行 Android 12 和 WebView 版本 89.0.4385.0 或更高版本的设备。

如需了解有关 Android 上的 WebView 远程调试的信息,请参阅 Android 设备的远程调试入门

其他资源

如需详细了解 SameSite 现代行为及其在 Chrome 和 WebView 中的部署,请访问 Chromium SameSite 更新页面。如果您在 WebView 或 Chromium 中发现了错误,则可以在公开的 Chromium 问题跟踪器中报告错误。

adb 备份限制

为了保护私有应用数据,Android 12 变更了 adb backup 命令的默认行为。对于以 Android 12 为目标平台的应用,用户运行 adb backup 命令时,从设备导出的任何其他系统数据都不包含应用数据。

如果您的测试或开发工作流程依赖于使用 adb backup 的应用数据,现在您可以选择通过在应用的清单文件中将 android:debuggable 设置为 true 来导出应用数据。

安全性

更安全地导出组件

“提供反馈”图标 我们非常期待收到您对这项关于导出组件的新要求的反馈。 请填写一份简短的调查问卷,告诉我们您的想法。具体而言,请告诉我们您的应用中的哪些用例受到此变更的影响。

如果您的应用以 Android 12 为目标平台,且包含使用 intent 过滤器activity服务广播接收器,您必须为这些应用组件显式声明 android:exported 属性。

警告:如果 activity、服务或广播接收器使用 intent 过滤器,并且未显式声明 android:exported 的值,则您的应用将无法在搭载 Android 12 的设备上进行安装。

如果您在使用 Android Studio 时尝试安装此类应用,Logcat 将显示以下错误消息:

Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
List of apks:
[0] '.../build/outputs/apk/debug/app-debug.apk'
Installation failed due to: 'null'

如果您的应用在需要声明 android:exported 的值时未进行此声明,则 Logcat 会提供以下错误消息:

Targeting S+ (version 10000 and above) requires that an explicit value for \
android:exported be defined when intent filters are present

以下代码段显示了一个服务示例,该服务包含 intent 过滤器并针对 Android 12 进行了正确配置:

<service android:name="com.example.app.backgroundService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.START_BACKGROUND" />
    </intent-filter>
</service>

待处理 intent 必须声明可变性

“提供反馈”图标 我们非常期待收到您对待处理 intent 新要求的反馈。 请填写一份简短的调查问卷,告诉我们您的想法。具体而言,请告诉我们您的应用中的哪些用例受到此变更的影响。

如果您的应用以 Android 12 为目标平台,您必须为您的应用创建的每个 PendingIntent 对象指定可变性。这项额外的要求可提高应用的安全性。

如需声明特定 PendingIntent 对象是否可变,请分别使用 PendingIntent.FLAG_MUTABLEPendingIntent.FLAG_IMMUTABLE 标志。如果您的应用试图在不设置任何可变标志的情况下创建 PendingIntent 对象,系统会抛出 IllegalArgumentException,并在 Logcat 中显示以下消息:

PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

尽可能创建不可变的待处理 intent

在大多数情况下,您的应用应创建不可变的 PendingIntent 对象,如以下代码段所示。如果 PendingIntent 对象不可变,则应用无法修改 intent 来调整调用 intent 的结果。

Kotlin

val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

然而,某些应用需要创建可变的 PendingIntent 对象:

如果您的应用创建了可变的 PendingIntent 对象,强烈建议您使用显式 intent 并填写 ComponentName。如此一来,每当另一个应用调用 PendingIntent 并将控制权传回您的应用时,应用中的相同组件都会启动。

测试待处理的 intent 可变性变更

如需确定您的应用是否缺少可变性声明,请在 Android Studio 中查找以下 lint 警告

Warning: Missing PendingIntent mutability flag [UnspecifiedImmutableFlag]

在开发者预览版计划期间,您可以通过关闭 PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED 应用兼容性标志来停用此系统行为以进行测试。

以不安全的方式启动嵌套 intent

为了提高平台安全性,Android 12 提供了一种调试功能,如果您的应用以不安全的方式启动嵌套 intent,此功能便会发出警告。嵌套 intent 是在其他 intent 中作为 extra 传递的 intent。如果您的应用同时执行以下两项操作,就会发生 StrictMode 违规行为。

  1. 您的应用从已传递的 intent 的 extra 中解封嵌套 intent。
  2. 您的应用立即使用该嵌套 intent 启动应用组件,例如将 intent 传递给 startActivity()startService()bindService()

配置应用以检测嵌套 intent 的不安全启动

如需检查您的应用中是否会以不安全的方式启动嵌套 intent,请在配置 VmPolicy 时调用 detectUnsafeIntentLaunch(),如以下代码段所示。如果您的应用检测到 StrictMode 违规行为,您可能需要停止应用的执行以保护潜在的敏感信息。

Kotlin

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}

Java

protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

更负责地使用 intent

您的应用可能会启动嵌套 intent,以便在应用的各个组件之间导航,或代表其他应用执行操作。如需在这两种情况下最大限度地降低出现 StrictMode 违规行为的可能性,请执行以下操作:

  • 嵌套 intent 的内部启动:确保这些组件不会被导出
  • 嵌套 intent 的跨应用启动:使用 PendingIntent 代替嵌套 intent。如此一来,当 PendingIntent 从包含它的 Intent 中解封时,应用组件可以使用调用进程的身份启动 PendingIntent。该配置允许提供程序应用向调用应用的任何组件(包括未导出的组件)发送回调。

    如需详细了解如何识别这种情况并变更您的应用,请参阅 Medium 上关于 Android 嵌套 intent 的博文。

性能

前台服务启动限制

以 Android 12 为目标平台的应用再也无法在后台运行时启动前台服务,但一些特殊情况除外。如果应用尝试在后台运行时启动前台服务,则会引发异常(少数特殊情况除外)。当您的应用在后台运行时,请考虑使用 WorkManager 来计划和启动工作。

如需详细了解您的应用会受到什么影响,以及如何根据这些变更来更新您的应用,请参阅前台服务启动限制指南。您还可以浏览 GitHub 上的 WorkManagerSample

无法通过服务或广播接收器创建通知 trampoline

“提供反馈”图标 我们非常期待收到您对通知 trampoline 行为的这些变更的反馈。 请填写一份简短的调查问卷,告诉我们您的想法。具体而言,请告诉我们您的应用中的哪些用例受到此变更的影响。

当用户与通知互动时,某些应用会启动应用组件来响应通知点按操作,此应用组件最终会启动用户最终看到并与之互动的 activity。此应用组件被称为通知 trampoline。

为了改进应用性能和用户体验,以 Android 12 为目标平台的应用无法从用作通知 trampoline 的服务广播接收器中启动 activity。换言之,当用户点按通知或通知中的操作按钮时,您的应用无法在服务或广播接收器内调用 startActivity()

当您的应用尝试从充当通知 trampoline 的服务或广播接收器启动 activity 时,系统会阻止启动该 activity 启动,并在 Logcat 中显示以下消息:

Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.

更新应用

如果您的应用从充当通知 trampoline 的服务或广播接收器启动 activity,请完成以下迁移步骤:

  1. 创建与一个下列 activity 关联的 PendingIntent 对象:

    • 用户点按通知后会看到的 activity(首选)。
    • Trampoline activity 或用于启动用户在点按通知后可以看到的 activity 的 activity。
  2. 构建通知的过程中,请使用您在上一步中创建的 PendingIntent 对象。

切换行为

在开发者预览版计划期间测试您的应用时,您可以使用 NOTIFICATION_TRAMPOLINE_BLOCK 应用兼容性标志启用和停用此限制。

限制非 SDK 接口

Android 12 包含更新后的受限制非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。

如果您的应用并非以 Android 12 为目标平台,其中一些变更可能不会立即对您产生影响。然而,虽然您目前仍可以使用一些非 SDK 接口(具体取决于应用的目标 API 级别),但只要您使用任何非 SDK 方法或字段,终归存在导致应用出问题的显著风险。

如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试您的应用来进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。然而,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,应请求新的公共 API

如需详细了解此 Android 版本中的变更,请参阅 Android 12 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制

自定义通知变更

Android 12 改变了完全自定义通知的外观。 以前,自定义通知能够使用整个通知区域并提供自己的布局和样式。由此产生的反模式可能会令用户困惑,或在不同设备上引发布局兼容性问题。

对于以 Android 12 为目标平台的应用,包含自定义内容视图的通知将不再使用完整通知区域;相反,系统会应用标准模板。此模板可确保自定义通知在所有状态下都与其他通知相同,例如,在收起状态下的通知图标和展开功能,以及在展开状态下的通知图标、应用名称和收起功能。此行为与 Notification.DecoratedCustomViewStyle 的行为几乎完全相同。

通过这种方式,Android 12 通过为用户提供可看到且熟悉的通知展开功能,使所有通知保持外观一致且易于浏览。

下图显示了标准模板中的自定义通知:

以下示例展示了在收起状态和展开状态下呈现的自定义通知:

Android 12 中的变更会影响某些定义 Notification.Style 的自定义子类的应用,或使用 Notification.Builder 的方法 setCustomContentView(RemoteViews)setCustomBigContentView(RemoteViews)setCustomHeadsUpContentView(RemoteViews) 的应用。

如果您的应用使用的是完全自定义的通知,我们建议您尽快使用新模板进行测试,并进行必要的调整:

  1. 启用自定义通知变更:

    1. 将应用的 targetSdkVersion 变更为 S 以启用新行为。
    2. 重新编译。
    3. 在搭载 Android 12 的设备或模拟器上安装您的应用。
  2. 测试所有使用自定义视图的通知,确保这些通知在通知栏中看起来符合预期。

  3. 请注意自定义视图规格。一般来说,提供给自定义通知的高度比之前小。在收起状态下,自定义内容的最大高度已从 106dp 减少到 48dp。此外,水平空间也减小了。

  4. 为了确保“浮动通知”状态看起来符合您的预期,请勿忘记将通知渠道的重要性提升至“高”(在屏幕中弹出)。

连接性

以 Android 12 及更高版本为目标平台的设备在具有硬件支持的设备上运行时,在与对等设备建立连接时,使用点对点连接不会断开与现有 Wi-Fi 的连接。如需检查是否支持此功能,请使用 WifiManager.isMultiStaConcurrencySupported()