行为变更:面向 Android 16 或更高版本的应用

与之前的版本一样,Android 16 包含可能影响您的应用的行为变更。以下行为变更专门适用于面向 Android 16 或更高版本的应用。如果您的应用面向 Android 16 或更高版本,则应在适用情况下修改应用以支持这些行为。

请务必同时查看影响所有在 Android 16 上运行的应用(无论应用的 targetSdkVersion 是多少)的行为变更列表。

用户体验和系统 UI

Android 16 (API level 36) 包含以下旨在创建更一致、更直观的用户体验的变更。

全面屏显示选择退出功能即将移除

Android 15 强制要求面向 Android 15 (API level 35) 的应用启用全面屏显示,但您的应用可以通过将 R.attr#windowOptOutEdgeToEdgeEnforcement 设置为 true 来选择退出。对于面向 Android 16 (API level 36) 的应用,R.attr#windowOptOutEdgeToEdgeEnforcement 已被弃用并停用,您的应用无法选择退出全面屏显示。

  • 如果您的应用面向 Android 16 (API level 36) 并在 Android 15 设备上运行,则 R.attr#windowOptOutEdgeToEdgeEnforcement 将继续有效。
  • 如果您的应用面向 Android 16 (API level 36) 并在 Android 16 设备上运行,则 R.attr#windowOptOutEdgeToEdgeEnforcement 将被停用。

为了在 Android 16 Beta 3 中进行测试,请确保您的应用支持全面屏显示,并移除对 R.attr#windowOptOutEdgeToEdgeEnforcement 的所有使用,以便您的应用也能在 Android 15 设备上支持全面屏显示。要支持全面屏显示,请参阅 ComposeViews 指南。

预测性返回需要迁移或选择退出

对于面向 Android 16 (API level 36) 或更高版本并在 Android 16 或更高版本设备上运行的应用,预测性返回系统动画(返回主屏幕、跨任务和跨 Activity)默认启用。此外,不再调用 onBackPressed,也不再分派 KeyEvent.KEYCODE_BACK

如果您的应用拦截了返回事件,但您尚未迁移到预测性返回,请更新您的应用以使用受支持的返回导航 API,或通过在应用的 AndroidManifest.xml 文件中的 <application><activity> 标签中将 android:enableOnBackInvokedCallback 属性设置为 false 来暂时选择退出。

预测性返回主屏幕动画。
预测性跨 Activity 动画。
预测性跨任务动画。

Elegant 字体 API 已弃用并停用

面向 Android 15 (API level 35) 的应用默认将 elegantTextHeight TextView 属性设置为 true,用更易读的字体替换紧凑字体。您可以通过将 elegantTextHeight 属性设置为 false 来覆盖此设置。

Android 16 弃用了 elegantTextHeight 属性,并且一旦您的应用面向 Android 16,该属性将被忽略。这些 API 控制的“UI 字体”正在停用,因此您应调整任何布局,以确保阿拉伯语、老挝语、缅甸语、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语文本呈现的一致性和未来适用性。

面向 Android 14 (API level 34) 及更低版本的应用,或面向 Android 15 (API level 35) 但通过将 elegantTextHeight 属性设置为 false 来覆盖默认设置的应用的 elegantTextHeight 行为。
面向 Android 16 的应用,或面向 Android 15 (API level 35) 但未通过将 elegantTextHeight 属性设置为 false 来覆盖默认设置的应用的 elegantTextHeight 行为。

核心功能

Android 16 (API level 36) 包含以下更改,这些更改修改或扩展了 Android 系统的各种核心功能。

固定速率工作调度优化

在面向 Android 16 之前,当 scheduleAtFixedRate 因处于有效的进程生命周期之外而错过任务执行时,当应用返回到有效的生命周期时,所有错过的执行都会立即执行。

面向 Android 16 时,当应用返回到有效的生命周期时,scheduleAtFixedRate 最多会立即执行一次错过的执行。预计此行为变更将改善应用性能。在您的应用中测试此行为,检查您的应用是否受到影响。您还可以使用应用兼容性框架并通过启用 STPE_SKIP_MULTIPLE_MISSED_PERIODIC_TASKS 兼容性标志进行测试。

设备外形

Android 16 (API level 36) 包含在大屏幕设备上显示应用时的以下变更。

自适应布局

随着 Android 应用现在可在各种设备(例如手机、平板电脑、折叠屏设备、台式机、汽车和电视)以及大屏幕上的窗口模式(例如分屏和桌面窗口模式)上运行,开发者应构建可适应任何屏幕和窗口大小(无论设备方向如何)的 Android 应用。在当今的多设备世界中,限制方向和可调整大小等范式过于严格。

忽略方向、可调整大小和宽高比限制

对于面向 Android 16 (API level 36) 的应用,Android 16 更改了系统管理方向、可调整大小和宽高比限制的方式。在最小宽度 >= 600dp 的显示屏上,这些限制不再适用。无论宽高比或用户偏好的方向如何,应用都会填充整个显示窗口,并且不使用柱状信箱。

此变更引入了新的标准平台行为。Android 正朝着一个模型迈进,在该模型中,应用应适应各种方向、显示尺寸和宽高比。固定方向或有限可调整大小等限制阻碍了应用的适应性,因此我们建议让您的应用具有自适应性,以提供最佳的用户体验。

您还可以使用应用兼容性框架并通过启用 UNIVERSAL_RESIZABLE_BY_DEFAULT 兼容性标志进行测试。

常见破坏性变更

忽略方向、可调整大小和宽高比限制可能会影响您的应用在某些设备上的 UI,特别是那些为锁定在纵向的小布局设计的元素:例如,布局拉伸以及屏幕外动画和组件等问题。任何关于宽高比或方向的假设都可能导致您的应用出现视觉问题。了解更多关于如何避免这些问题并改进应用的自适应行为的信息。

允许设备旋转会导致更多 Activity 重建,如果未正确保存,这可能会导致用户状态丢失。了解如何在保存 UI 状态中正确保存 UI 状态。

实现详情

在全屏和多窗口模式下,大型屏幕设备将忽略以下清单属性和运行时 API

screenOrientationsetRequestedOrientation()getRequestedOrientation() 的以下值将被忽略

  • portrait
  • reversePortrait
  • sensorPortrait
  • userPortrait
  • landscape
  • reverseLandscape
  • sensorLandscape
  • userLandscape

关于显示可调整大小,android:resizeableActivity="false"android:minAspectRatioandroid:maxAspectRatio 不会生效。

对于面向 Android 16 (API level 36) 的应用,应用的方向、可调整大小和宽高比限制在大屏幕上默认会被忽略,但每个尚未完全准备好的应用都可以通过选择退出(这会导致进入兼容模式的先前行为)来暂时覆盖此行为。

例外情况

在以下情况下,Android 16 的方向、可调整大小和宽高比限制不适用

  • 游戏(基于 android:appCategory 标志)
  • 用户在设备的宽高比设置中明确选择启用应用的默认行为
  • 小于 sw600dp 的屏幕

暂时选择退出

要选择退出特定的 Activity,请声明 PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY 清单属性

<activity ...>
  <property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" />
  ...
</activity>

如果您的应用有太多部分尚未为 Android 16 做好准备,您可以在应用级别应用相同的属性来完全选择退出

<application ...>
  <property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" />
</application>

健康与健身

Android 16 (API level 36) 包含以下与健康和健身数据相关的变更。

健康与健身权限

对于面向 Android 16 (API level 36) 或更高版本的应用,BODY_SENSORS 权限使用 android.permissions.health 下更精细的权限,Health Connect 也使用这些权限。从 Android 16 开始,以前需要 BODY_SENSORSBODY_SENSORS_BACKGROUND 的任何 API 都需要相应的 android.permissions.health 权限。这会影响以下数据类型、API 和前台服务类型:

如果您的应用使用这些 API,则应请求相应的精细权限

这些权限与保护访问 Health Connect(Android 健康、健身和保健数据的数据存储)中数据的权限相同。

移动应用

迁移到使用 READ_HEART_RATE 和其他精细权限的移动应用还必须声明一个 Activity 以显示应用的隐私政策。这与 Health Connect 的要求相同。

连接性

Android 16 (API level 36) 在蓝牙堆栈中包含以下更改,以改善与外围设备的连接。

用于处理绑定丢失和加密更改的新 Intent

作为改进的绑定丢失处理的一部分,Android 16 还引入了 2 个新 Intent,以便应用更好地了解绑定丢失和加密更改。

面向 Android 16 的应用现在可以

  • 在检测到远程绑定丢失时接收 ACTION_KEY_MISSING Intent,从而允许它们提供更具信息性的用户反馈并采取适当的操作。
  • 每当链接的加密状态发生变化时,都会收到 ACTION_ENCRYPTION_CHANGE intent。这包括加密状态变化、加密算法变化和加密密钥大小变化。如果稍后收到 ACTION_ENCRYPTION_CHANGE intent 时链接成功加密,应用必须认为绑定已恢复。

如果您的应用当前使用自定义机制处理绑定丢失,请迁移到新的 ACTION_KEY_MISSING intent 来检测和管理绑定丢失事件。我们建议您的应用引导用户在启动设备取消配对和重新配对之前确认远程设备是否在范围内。

此外,如果在收到 ACTION_KEY_MISSING intent 后设备断开连接,您的应用应注意重新连接到该设备,因为该设备可能不再与系统绑定。

移除蓝牙绑定的新方法

所有面向 Android 16 的应用现在可以使用 CompanionDeviceManager 中的公共 API 取消配对蓝牙设备。如果伴侣设备作为 CDM 关联进行管理,则应用可以使用关联设备上的新 removeBond(int) API 触发蓝牙绑定移除。应用可以通过监听蓝牙设备广播事件 ACTION_BOND_STATE_CHANGED 来监控绑定状态变化。

安全性

Android 16 (API level 36) 包含以下安全性更改。

MediaStore 版本锁定

对于面向 Android 16 或更高版本的应用,MediaStore#getVersion() 现在对每个应用都是唯一的。这消除了版本字符串中的识别属性,以防止滥用和用于指纹识别技术。应用不应对此版本的格式做任何假设。应用在使用此 API 时应已处理版本更改,并且在大多数情况下不需要更改其当前行为,除非开发者试图推断超出此 API 预期范围的额外信息。

更安全的 Intent

Safer Intents 功能是一项多阶段的安全倡议,旨在提高 Android 的 Intent 解析机制的安全性。目标是通过在 Intent 处理期间添加检查和过滤不符合特定条件的 Intent 来保护应用免受恶意操作。

Android 15 中,该功能侧重于发送应用,现在在 Android 16 中,将控制权转移到接收应用,允许开发者使用其应用清单选择加入严格的 Intent 解析。

正在实施两个关键变更:

  1. 显式 Intent 必须与目标组件的 Intent 过滤器匹配:如果一个 Intent 显式地以某个组件为目标,则它应该与该组件的 Intent 过滤器匹配。

  2. 没有指定操作的 Intent 不能匹配任何 Intent 过滤器:未指定操作的 Intent 不应解析到任何 Intent 过滤器。

这些变更仅适用于涉及多个应用的情况,不影响单个应用内的 Intent 处理。

影响

选择加入的性质意味着开发者必须在其应用清单中明确启用它才能生效。因此,该功能的影响将仅限于其开发者符合以下条件的应用:

  • 了解 Safer Intents 功能及其优势。
  • 主动选择将更严格的 Intent 处理实践纳入其应用。

这种选择加入的方法最大程度地降低了破坏可能依赖当前安全性较低的 Intent 解析行为的现有应用的风险。

虽然在 Android 16 中的初始影响可能有限,但 Safer Intents 倡议有一个在未来 Android 版本中产生更广泛影响的路线图。计划最终将严格的 Intent 解析设为默认行为。

Safer Intents 功能通过使恶意应用更难利用 Intent 解析机制中的漏洞,有可能显著增强 Android 生态系统的安全性。

然而,向选择退出和强制执行的过渡必须仔细管理,以解决与现有应用潜在的兼容性问题。

实现

开发者需要使用其应用清单中的 intentMatchingFlags 属性显式启用更严格的 Intent 匹配。以下是一个示例,其中该功能在整个应用中是选择加入的,但在接收器上被禁用/选择退出:

<application android:intentMatchingFlags="enforceIntentFilter">
    <receiver android:name=".MyBroadcastReceiver" android:exported="true" android:intentMatchingFlags="none">
        <intent-filter>
            <action android:name="com.example.MY_CUSTOM_ACTION" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.example.MY_ANOTHER_CUSTOM_ACTION" />
        </intent-filter>
    </receiver>
</application>

更多关于支持的标志

标志名称 说明
enforceIntentFilter 对传入 Intent 强制执行更严格的匹配
none 禁用所有传入 Intent 的特殊匹配规则。当指定多个标志时,通过优先处理“none”标志来解决冲突的值。
allowNullAction 放松匹配规则,允许没有操作的 Intent 进行匹配。此标志与“enforceIntentFilter”结合使用可实现特定行为。

测试和调试

当强制执行生效时,如果 Intent 调用者正确填充了 Intent,应用应能正常工作。但是,被阻止的 Intent 将会触发警告日志消息,例如 "Intent does not match component's intent filter:""Access blocked:",带有标签 "PackageManager."。这表示可能影响应用并需要注意的潜在问题。

Logcat 过滤

tag=:PackageManager & (message:"Intent does not match component's intent filter:" | message: "Access blocked:")

隐私权

Android 16 (API level 36) 包含以下隐私更改。

本地网络权限

具有 INTERNET 权限的任何应用都可以访问 LAN 上的设备。这使得应用可以轻松连接到本地设备,但也存在隐私隐患,例如形成用户指纹以及充当位置代理。

本地网络保护项目旨在通过在新的运行时权限后门控本地网络的访问来保护用户的隐私。

发布计划

此更改将在两次发布之间部署,分别是 25Q2 和待定 (TBD)。开发者务必遵循 25Q2 的此指南并分享反馈,因为这些保护措施将在后续的 Android 版本中强制执行。此外,他们需要使用以下指南更新依赖于隐式本地网络访问的场景,并为用户拒绝和撤销新权限做好准备。

影响

在当前阶段,LNP 是一项选择加入功能,这意味着只有选择加入的应用会受到影响。选择加入阶段的目标是让应用开发者了解其应用的哪些部分依赖于隐式本地网络访问,以便他们可以为下一个版本准备好权限保护。

如果应用通过以下方式访问用户的本地网络,则会受到影响:

  • 直接或通过库在本地网络地址上使用原始套接字(例如 mDNS 或 SSDP 服务发现协议)
  • 使用访问本地网络的框架级别类(例如 NsdManager)

发送到接收自本地网络地址的流量需要本地网络访问权限。下表列出了一些常见情况:

应用低级别网络操作 需要本地网络权限
建立出站 TCP 连接
接受入站 TCP 连接
发送 UDP 单播、多播、广播

  • 这些限制是在网络堆栈深层实现的,因此它们适用于所有网络 API。这包括在原生或托管代码中创建的套接字、Cronet 和 OkHttp 等网络库以及基于这些库实现的任何 API。尝试解析本地网络上的服务(即带有 .local 后缀的服务)将需要本地网络权限。
  • 注意: 需要本地网络访问的 Android Webview 生成的流量将继承宿主应用的权限状态。

如果设备的 DNS 服务器在本地网络上,则与其之间的流量(端口 53)不需要本地网络访问权限。

使用 Output Switcher 作为其应用内选择器的应用不需要本地网络权限(更多指南将在 2025 年第四季度发布)。

  1. 注意: 许多媒体投射场景依赖于本地网络访问,并将受到此变更的影响。但是,并非所有提供投射功能的应用都需要请求新权限。有关处理投射场景的未来 API 和指南将在 25Q4 提供。
  2. 开发者指南(选择加入)
  3. 要选择加入本地网络限制,请执行以下操作:

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. 将设备刷入 25Q2 Beta 3 或更高版本的构建。

安装要测试的应用。

在 adb 中切换 Appcompat 标志

  1. 重新启动设备
  2. 现在您的应用对本地网络的访问受到限制,任何访问本地网络的尝试都将导致套接字错误。如果您正在使用在应用进程之外执行本地网络操作的 API(例如 NsdManager),在选择加入阶段它们不会受到影响。

确保应用在其清单中声明了 NEARBY_WIFI_DEVICES 权限。

转到设置 > 应用 > [应用名称] > 权限 > 附近的设备 > 允许

注意: 在未来的 Android 版本中,此功能将受到附近设备权限组中的权限的保护。 现在您的应用对本地网络的访问应该已恢复,并且您的所有场景应该像在选择加入之前一样工作。 一旦开始强制执行本地网络保护,应用的如下网络流量将受到影响。 权限
出站 LAN 请求 出站/入站 Internet 请求 出站/入站 Internet 请求 出站/入站 Internet 请求
入站 LAN 请求 已授予 出站/入站 Internet 请求 已授予

工作

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

失败

未授予

工作

sendto failed: EPERM (Operation not permitted)

sendto failed: ECONNABORTED (Operation not permitted)

失败

使用以下命令关闭 App-Compat 标志

错误

这些限制引起的错误将在调用套接字向本地网络地址调用 send 或其变体时返回。

  • 错误示例
  • 本地网络定义
  • 在此项目中,本地网络指利用广播能力网络接口(例如 Wi-Fi 或以太网),但不包括蜂窝 (WWAN) 或 VPN 连接的 IP 网络。
  • 以下被视为本地网络:
  • IPv4

169.254.0.0/16 // Link Local

  • 100.64.0.0/10 // CGNAT
  • 10.0.0.0/8 // RFC1918
  • 172.16.0.0/12 // RFC1918
  • 192.168.0.0/16 // RFC1918

IPv6

本地链接

直接连接的路由