行为变更:以 Android 17 或更高版本为目标平台的应用

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

无论应用的 targetSdkVersion 为何,都请务必查看对 Android 17 上运行的所有应用都有影响的行为变更列表。

用户体验和系统界面

Android 17 包含以下旨在打造更一致、更直观的用户体验的变更。

内存限制 widget

从 Android 17 开始,对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,系统会针对 RemoteViews Parcel 中存在的位图和图标的总内存使用量强制执行严格的内存限制 (1.5 * 屏幕宽度 * 屏幕高度 * 4)。如果超出这些限制,系统会抛出致命的 IllegalArgumentException 并导致应用进程崩溃。

如需了解详情,请参阅 UpdateAppWidget

核心功能

Android 17 包含以下变更,这些变更会修改或扩展 Android 系统的各种核心功能。

MessageQueue 的新无锁实现

从 Android 17 开始,以 Android 17(API 级别 37) 或更高版本为目标平台的应用会收到 android.os.MessageQueue 的新无锁实现。新实现可提升性能并减少丢帧,但可能会破坏反映 MessageQueue 私有字段和方法的客户端。

如需了解详情(包括缓解措施),请参阅 MessageQueue 行为变更指南

静态 final 字段现在不可修改

在以 Android 17(API 级别 37)或更高版本为目标平台的 Android 17 或更高版本上运行的应用无法更改 static final 字段。如果应用尝试使用反射更改 static final 字段,则会导致 IllegalAccessException。尝试通过 JNI API(例如 SetStaticLongField())修改其中一个字段会导致应用崩溃。

无障碍

Android 17 进行了以下变更,以改进无障碍功能。

复杂 IME 实体键盘输入的无障碍支持

此功能引入了新的 AccessibilityEventTextAttribute API,以增强 CJKV 语言输入的屏幕阅读器语音反馈。CJKV IME 应用现在可以指示在文本撰写期间是否已选择文本转换候选内容。具有编辑字段的应用可以在发送文本更改无障碍事件时指定文本更改类型。例如,应用可以指定在文本撰写期间发生了文本更改,或者文本更改是由提交导致的。这样做可让屏幕阅读器等无障碍服务根据文本修改的性质提供更精确的反馈。

应用采用量

  • IME 应用:在编辑字段中设置正在撰写的文本时,IME 可以使用 TextAttribute.Builder.setTextSuggestionSelected() 来指明是否选择了特定的候选转化。

  • 具有“编辑字段”权限的应用:维护自定义 InputConnection 的应用可以通过调用 TextAttribute.isTextSuggestionSelected() 来检索候选选择数据。然后,这些应用在调度 TYPE_VIEW_TEXT_CHANGED 事件时应调用 AccessibilityEvent.setTextChangeTypes()。以 Android 17(API 级别 37)为目标平台且使用标准 TextView 的应用默认会启用此功能。(也就是说,TextView 将负责从 IME 检索数据,并在向无障碍服务发送事件时设置文本更改类型)。

  • 无障碍服务:处理 TYPE_VIEW_TEXT_CHANGED 事件的无障碍服务可以调用 AccessibilityEvent.getTextChangeTypes() 来识别修改的性质,并相应地调整其反馈策略。

隐私权

Android 17 包含以下变更,旨在提升用户隐私保护。

已启用 ECH(加密客户端 Hello)

Android 17 引入了对加密 Client Hello (ECH) 的平台支持。ECH 是一项 TLS 扩展,可通过加密 TLS 握手中的服务器名称指示 (SNI) 来增强用户隐私保护。这种加密有助于防止网络观察者轻易识别出您的应用所连接的特定网域。

对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,ECH 用于 TLS 连接。只有当应用使用的网络库(例如 HttpEngine、WebView 或 OkHttp)已集成 ECH 支持,并且远程服务器也支持 ECH 协议时,ECH 才会处于有效状态。如果无法协商 ECH,客户端会发送包含随机内容的 ECH 扩展程序(一种称为 ECH GREASE 的机制)。如需详细了解 ECH GREASE 的运作方式,请参阅 RFC 9849

为了允许应用自定义此行为,Android 17 向网络安全配置文件添加了一个新的 <domainEncryption> 元素。开发者可以在 <base-config><domain-config> 标记中使用 <domainEncryption>,以全局或按网域选择 ECH 模式(例如 "enabled""disabled")。

如需了解详情,请参阅加密的客户端 Hello 文档。

以 Android 17 为目标平台的应用需要本地网络权限

Android 17 引入了 ACCESS_LOCAL_NETWORK 运行时权限,以保护用户免遭未经授权的本地网络访问。由于此权限属于现有的 NEARBY_DEVICES 权限组,因此已授予其他 NEARBY_DEVICES 权限的用户不会再次收到提示。这项新要求可防止恶意应用利用不受限制的本地网络访问权限进行隐蔽的用户跟踪和指纹识别。通过声明和请求此权限,您的应用可以发现并连接到局域网 (LAN) 中的设备,例如智能家居设备或投屏接收器。

以 Android 17(API 级别 37)或更高版本为目标平台的应用现在可以通过两种方式与 LAN 设备保持通信:采用系统介导的、可保护隐私的设备选择器来跳过权限提示,或者在运行时明确请求这项新权限来保持本地网络通信。

如需了解详情,请参阅本地网络权限文档。

在实体设备上隐藏密码

如果应用以 Android 17(API 级别 37)或更高版本为目标平台,并且用户使用的是实体输入设备(例如外接键盘),则 Android 操作系统会将新的 show_passwords_physical 设置应用于密码字段中的所有字符。默认情况下,该设置会隐藏所有密码字符。

Android 系统会显示最后输入的密码字符,以帮助用户查看密码是否输入错误。不过,如果使用较大的外接键盘,则不太需要这样做。此外,配备外接键盘的设备通常具有更大的显示屏,这会增加他人看到所输入密码的风险。

如果用户使用的是设备的触屏,系统会应用新的 show_passwords_touch 设置。

针对标准短信的 OTP 保护

从 Android 17 开始,Android 将扩展其短信动态密码保护功能,以适用于标准短信(包含未使用 WebOTP 或 SMS Retriever 格式的动态密码的短信)。对于以 Android 17(API 级别 37)或更高版本为目标平台的大多数应用,这些短信在收到后三小时内无法使用。此延迟旨在帮助防止 OTP 劫持。在这 3 小时的延迟期间,SMS_RECEIVED_ACTION 广播会被保留,并且 SMS 提供方数据库查询会被过滤。延迟结束后,这些应用即可访问相应短信。

某些应用(例如默认的短信助理应用、已连接的设备配套应用等)不受此延迟限制。所有依赖于读取短信消息来提取 OTP 的应用都应改用 SMS RetrieverSMS User Consent API,以确保功能能够继续正常运行。

安全

Android 17 对设备和应用安全性进行了以下改进。

活动安全性

在 Android 17 中,平台继续向“默认安全”架构转变,引入了一系列旨在缓解严重程度较高的漏洞利用(例如网络钓鱼、交互劫持和混淆代理攻击)的增强功能。此更新要求开发者明确选择启用新的安全标准,以保持应用兼容性和用户保护。

对开发者的主要影响包括:

  • BAL 安全加固和改进的选择启用机制:我们正在通过将保护范围扩展到 IntentSender 来完善后台 Activity 启动 (BAL) 限制。开发者必须弃用旧版 MODE_BACKGROUND_ACTIVITY_START_ALLOWED 常量。相反,您应采用精细的控制措施,例如 MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE,该措施会将 activity 启动限制在调用应用可见的场景中,从而显著减小攻击面。
  • 采用工具:开发者应利用严格模式和更新后的 lint 检查来识别旧版模式,并确保应用符合未来的目标 SDK 要求。

默认启用 CT

如果应用以 Android 17(API 级别 37)或更高版本为目标平台,则默认启用证书透明度 (CT)。(在 Android 16 上,CT 可用,但应用必须选择启用。)

更安全的原生 DCL - C

如果您的应用以 Android 17(API 级别 37)或更高版本为目标平台,则 Android 14 中针对 DEX 和 JAR 文件引入的更安全的动态代码加载 (DCL) 保护功能现在也适用于原生库。

使用 System.load() 加载的所有原生文件都必须标记为只读。否则,系统会抛出 UnsatisfiedLinkError

我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。

限制 CP2 数据视图中的 PII 字段

对于以 Android 17(API 级别 37)及更高级别为目标平台的应用,联系人提供程序 2 (CP2) 会限制数据视图中包含某些个人身份信息 (PII) 的列。启用此变更后,系统会从数据视图中移除这些列,以增强用户隐私保护。 受限列包括:

使用 ContactsContract.Data 中这些列的应用可以通过与 RAW_CONTACT_ID 联接,改为从 ContactsContract.RawContacts 中提取这些列。

在 CP2 中强制执行严格的 SQL 检查

对于以 Android 17(API 级别 37)及更高版本为目标平台的应用,当在没有 READ_CONTACTS 权限的情况下访问 ContactsContract.Data 表时,联系人提供程序 2 (CP2) 会强制执行严格的 SQL 查询验证。

在此更改之后,如果应用没有 READ_CONTACTS 权限,则在查询 ContactsContract.Data 表时,系统会设置 StrictColumnsStrictGrammar 选项。如果查询使用的模式与这些模式不兼容,则会被拒绝并导致抛出异常。

智能

Android 17 针对系统智能做出了以下变更。

弃用 setContentCaptureEnabled

某些设备默认启用内容捕获功能,以便设备端 AI 功能分析屏幕内容,从而提供智能体验。

从 Android 17 开始,ContentCaptureManager.setContentCaptureEnabled(boolean) API 方法已被废弃。对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,调用 setContentCaptureEnabled(false) 不再停用内容捕获。

如果您的应用需要继续停用内容捕获或限制系统捕获屏幕内容,则必须改用 FLAG_SECURE 窗口布局参数。

如需停用内容捕获,请在窗口上设置 FLAG_SECURE 标志,如以下示例所示:

Kotlin

window.setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
);

如需了解详情,请参阅 WindowManager.LayoutParams.FLAG_SECURE 参考文档。

媒体

Android 17 针对媒体行为做了以下更改。

后台音频安全加固

从 Android 17 开始,音频框架对后台音频互动(包括音频播放、音频焦点请求和音量更改 API)强制执行限制,以确保这些更改是由用户有意发起的。

部分音频限制适用于所有应用。不过,如果应用以 Android 17(API 级别 37)为目标平台,则限制会更加严格。如果这些应用在后台运行时与音频互动,则必须有前台服务在运行。此外,应用还必须满足以下一项或两项要求:

  • 前台服务必须具有仅在使用时授予的权限 (WIU)。
  • 应用必须具有精确闹钟权限,并且正在与 USAGE_ALARM 音频流互动。

如需了解详情(包括缓解措施),请参阅后台音频安全加固

设备规格

Android 17 包含以下变更,可改善各种尺寸和外形规格的设备上的用户体验。

平台 API 变更:忽略大屏设备 (sw>=600dp) 上的屏幕方向、尺寸调整和宽高比限制

我们在 Android 16 中引入了平台 API 变更,以忽略以 API 级别 36 或更高级别为目标的应用在大屏 (sw >= 600dp) 设备上的屏幕方向、宽高比和尺寸调整能力限制。开发者可以选择使用 SDK 36 停用这些变更,但对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,此停用选项将不再可用。

如需了解详情,请参阅忽略了有关屏幕方向和可调整大小性的限制

连接

Android 17 引入了以下变更,以提高一致性并与蓝牙 RFCOMM 套接字的标准 Java InputStream 行为保持一致。

针对 RFCOMM 的一致 BluetoothSocket read() 行为

对于以 Android 17(API 级别 37)为目标平台的应用,从基于 RFCOMM 的 BluetoothSocket 获取的 InputStreamread() 方法现在在套接字关闭或连接断开时返回 -1

此变更使 RFCOMM 套接字行为与 LE CoC 套接字保持一致,并与标准 InputStream.read() 文档保持一致,该文档指出,当到达数据流末尾时,系统会返回 -1

仅依靠捕获 IOException 来跳出读取循环的应用可能会受到此变更的影响,应更新 BluetoothSocket 读取循环以明确检查 -1 的返回值。这可确保在远程设备断开连接或套接字关闭时,循环正确终止。如需查看推荐的实现示例,请参阅传输蓝牙数据指南中的代码段