Android P 行为变更

Android P 对 Android 系统进行了多项变更。 其中大部分变更会影响所有应用,而不论应用针对的是何种版本的 Android。 不过,有几项变更仅影响针对 Android P 的应用。 为清楚起见,本页面分为两个部分:针对所有 API 级别的应用针对 Android P 的应用

在 Android P 上运行的所有应用

当应用运行在 Android P 平台上时,这些行为变更将影响所有应用,无论这些应用是针对哪个 API 级别构建。 所有开发者都应查看这些变更,并修改其应用以正确支持这些变更(如果适用)。

后台应用中的输入和数据隐私

Android P 通过限制后台应用访问用户输入和传感器数据的能力增强了隐私性。 如果您的应用在运行 Android P 的设备上在后台运行,系统将对您的应用施加以下限制:

  • 您的应用不能访问麦克风或摄像头。
  • 使用连续报告模式的传感器(例如加速度计和陀螺仪)不会接收事件。
  • 使用发送变化时一次性报告模式的传感器不会接收事件。

如果您的应用需要在运行 Android P 的设备上检测传感器事件,请使用前台服务

注:对 SensorManager 的某个实例调用 flush() 的应用不会受此变更影响。

设备安全性变更

运行 Android P 的设备提供密钥轮转和系统调用保护。 无论应用的目标 API 级别为何,这些变更都能增强应用的安全性。 如需了解更多详情,请参阅安全行为变更页面上对所有应用做出的变更。

加密变更

Android P 针对加密算法的实现和处理引入了几项变更。

参数和算法的 Conscrypt 实现

Android P 在 Conscrypt 中实现了更多的算法参数{: .external-link}。 这些参数包括: AES、DESEDE、OAEP 和 EC。 这些参数和许多算法的 Bouncy Castle 版本{: .external-link} 在 Android P 中已被弃用。

注:EC 参数的 Conscrypt 实现仅支持已命名的曲线。

如果您的应用以 Android 8.1(API 级别 27)或更低版本为目标,则在请求上述已弃用算法的 Bouncy Castle 实现时,您将收到一条警告消息。 然而,如果您以 Android P 为目标,则这些请求会各自引发 NoSuchAlgorithmException

其他变更

Android P 引入了其他几项加密变更:

  • 使用 PBE 密钥时,如果 Bouncy Castle 需要初始化矢量 (IV),而您的应用未提供 IV,则会收到一条警告消息。
  • ARC4 加密的 Conscrypt 实现允许您指定 ARC4/ECB/NoPaddingARC4/NONE/NoPadding
  • Crypto Java 加密架构 (JCA) 提供程序现已被移除。 因此,如果您的应用调用 SecureRandom.getInstance("SHA1PRNG", "Crypto"),将会发生 NoSuchProviderException
  • 如果您的应用从大于密钥结构的缓冲区中解析 RSA 密钥,将不会再发生异常。

应用兼容性变更

为帮助确保应用稳定性和兼容性,此平台对某些非 SDK 函数和字段的使用进行了限制;无论您是直接访问这些函数和字段,还是通过反射或 JNI 访问,这些限制均适用。 在 Developer Preview 1 中,您的应用可以继续访问这些受限的接口;该平台通过 toast 和日志条目提醒您注意这些接口。 如果您的应用显示这样的 toast,则必须寻求受限接口之外的其他实现策略。 如果您认为没有可行的替代策略,您可以提交错误 以请求重新考虑此限制。

对于非 SDK 接口的限制包含了更多重要信息。 您应查阅该信息以确保您的应用继续正常工作。

ICU 库更新

平台中使用的 ICU 库版本已从 Android 8.0(API 级别 26)和 8.1(API 级别 27)中的 ICU 58 更新至 ICU 60。

ICU 用于提供 android.icu package 下的公开 API,供 Android 平台内部用来提供国际化支持。 例如,它用于实现 java.util、java.text 和 android.text 格式的 Android 类。 此版本包含许多细微但很有用的变更,例如 Emoji 5.0 数据支持,改进了日期/时间格式,详见 ICU 59 和 ICU 60 版本说明中的介绍。

您应特别注意以下几点:

  • 平台处理时区的方式已发生更改。
    • 平台能够更好地处理 GTM 和 UTC,不再将 UTC 与 GMT 混为一谈。

      ICU 现在提供 GMT 和 UTC 的翻译版时区名称。 此变更会影响“GMT”、“Etc/GMT”、“Etc/UTC”、“UTC”和“Zulu”之类时区的 android.icu 格式和解析行为。

    • java.text.SimpleDateFormat 现在使用 ICU 提供 UTC /GMT 的显示名称,这意味着:
      • 对于许多语言区域而言,设置 zzzz 的格式将会生成很长的本地化字符串。 之前,对于 UTC 时区,它会生成“UTC”,而对于 GMT,则会生成“GMT+00:00”之类的字符串。
      • 解析 zzzz 可识别“Universal Coordinated Time”和“Greenwich Mean Time”之类的字符串。
      • 在所有语言里,如果应用接受“UTC”或“GMT+00:00”作为 zzzz 的输出,则可能会遇到兼容性问题。
    • java.text.DateFormatSymbols.getZoneStrings() 的行为已变更:
      • SimpleDateFormat 类似,现在,UTC 和 GMT 也有长名称。 对于 UTC 时区,DST 类型的时区名称(例如“UTC”、“Etc/UTC”和“Zulu”)变为 GMT+00:00(而不是硬编码字符串 UTC),这是在没有其他名称可用时的标准回退。
      • 某些时区 ID 被正确地识别为其他地区的同义词,因此,Android 能够查找过时时区 ID(例如 Eire)对应的字符串,而之前无法解决此问题。
    • 亚洲/河内不再是可识别的时区。 因此,java.util.TimeZones.getAvailableIds() 不再返回此值,java.util.TimeZone.getTimeZone() 也不再识别它。 此行为与现有的 android.icu 行为相符。
  • android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) 函数甚至在解析合法货币文本时也会引发 ParseException。 通过对 PLURALCURRENCYSTYLE 类型的货币文本使用自 Android 7.0(API 级别 24)以来所提供的 NumberFormat.parseCurrency,可避免此问题。

不再支持 Android 安全加密文件

  • Android 安全加密文件 (ASEC) 最初是在 Android 2.2(API 级别 8)中引入,用于支持原始的 SD 卡加载应用功能。 Android 6.0(API 级别 23)替换并弃用了 ASEC,引入了“可采用的 SD 卡”功能。

  • Android 8.0(API 级别 26)禁止在 ASEC 中安装新应用。 此 Developer Preview 则完全移除了 ASEC 功能。

测试套件版本号变更

移除了 TestSuiteBuilder 类中的 addRequirements() 函数,TestSuiteBuilder 类本身也已弃用。 addRequirements() 函数要求开发者提供类型为隐藏 API 的参数,结果令 API 失效。

从框架移除的测试库

在 Android 8.1(API 级别 27)和更低版本中,Android 框架提供了 ActivityInstrumentationTestCase2 等若干类,您可以利用这些类在应用中创建测试。 编译时,这些类可在针对 android.jar 构建时使用。 这种内置测试架构尽管方便,但需要您针对 android.jar 提供的 JUnit 版本进行测试,这会使构建和测试依赖其他 JUnit 版本的依赖项变得困难。

为了让您能够更灵活地构建和测试自定义或第三方逻辑,Android P 从框架中移除了测试类。 但测试库仍可作为可选依赖项使用。 旧版测试库页面介绍了如何在 Android P 中使用它们。

如需了解有关如何测试 Android 应用的更多信息,请参阅在 Android 上测试应用

Java UTF 解码器

UTF-8 是 Android 中的默认字符集。 UTF-8 字节序列可由 String(byte[] bytes) 之类的 String 构造函数解码。 Android P 中的 UTF-8 解码器更严格,其遵循 Unicode 标准,也即:

  • 非最短形式的 UTF-8(例如 <C0, AF>)现在被视为格式不正确。
  • 替代形式的 UTF-8(例如 U+D800..U+DFFF)现在被视为格式不正确。
  • 最大的子部分被单个 U+FFFD 取代。 例如,在字节序列“41 C0 AF 41 F4 80 80 41”中,最大子部分为“C0”、“AF”和“F4 80 80”。其中“F4 80 80”可以是“F4 80 80 80”的初始子序列,但“C0”不能是任何形式正确的代码单位序列的初始子序列。 因此,输出应为“A\ufffd\ufffdA\ufffdA”。
  • 要在 Android P 中解码修改后的 UTF-8/CESU-8 序列,请使用 DataInputStream.readUTF() 函数或 NewStringUTF() JNI 函数。

使用证书的主机名验证

RFC 2818 中介绍了两种对照证书匹配域名的方法—使用 subjectAltName (SAN) 扩展程序中的可用名称,或者在没有 SAN 扩展程序的情况下,回退到 commonName (CN)。

然而,在 RFC 2818 中,回退到 CN 已被弃用。因此,Android 不再回退到使用 CN。 要验证主机名,服务器必须出示具有匹配 SAN 的证书。 不包含与主机名匹配的 SAN 的证书不再被信任。

网络地址查询可能会导致网络违规

要求名称解析的网络地址查询可能会涉及网络 I/O 并被视为阻塞性操作。 对于主线程的阻塞性操作可能会导致停顿或卡顿。

StrictMode 类是一个有助于开发者检测代码问题的开发工具。 现在,StrictMode 可以检测需要名称解析的网络地址查询所导致的网络违规。

开发者在交付应用时不应启用 StrictMode。 否则,其应用可能会遭遇新的异常,例如,在使用 detectNetwork()detectAll() 函数获取用于检测网络违规的政策时,会出现 NetworkOnMainThreadException

解析数字 IP 地址不被视为阻塞性操作。 数字 IP 地址解析的工作方式与 Android P 以前的平台版本中所采用的方式相同。

套接字标记

在 Android P 以前的平台版本上,如果使用 setThreadStatsTag() 函数标记某个套接字,则当使用带 ParcelFileDescriptor 容器的 binder IPC 将其发送给其他进程时,套接字会被取消标记。

从 Android P 开始,利用 binder IPC 将套接字发送至其他进程时,其标记将得到保留。 此变更可能影响网络流量统计,例如,使用queryDetailsForUidTag() 函数时。 您可以通过先调用 untagSocket() 然后再将套接字发送至其他进程,保留以前的行为。

报告的套接字中可用字节数

在调用 shutdownInput() 函数后调用 available() 函数会返回 0

更详尽的 VPN 网络功能报告

在 Android P 以前的平台版本中,NetworkCapabilities 类仅报告 VPN 的有限信息,例如 TRANSPORT_VPN,但会省略 NET_CAPABILITY_NOT_VPN。 这种情形导致应用开发者难以确定使用 VPN 是否会导致对用户收费。 例如,检查 NET_CAPABILITY_NOT_METERED 并不能确定底层网络是否按流量计费。

从 Android P 开始,当 VPN 调用 setUnderlyingNetworks() 函数时,Android 系统将会合并任何底层网络的传输和能力并返回 VPN 网络的有效网络能力作为结果。

自 Android P 开始,已经检查 NET_CAPABILITY_NOT_METERED 的应用开发者将收到关于 VPN 网络能力和底层网络的信息。

应用无法再访问 xt_qtaguid 文件夹中的文件

不再允许应用直接读取 /proc/net/xt_qtaguid 文件夹中的文件。 这样做是为了确保与某些在发布时运行 Android P、但未提供这些文件的设备保持一致。

依赖这些文件的公开 API TrafficStatsNetworkStatsManager 继续按照预期方式运行。 然而,不受支持的 cutils 功能(例如 qtaguid_tagSocket())在不同设备上可能不会按照预期方式运行 — 甚至根本不运行。

现在,强制执行 FLAG_ACTIVITY_NEW_TASK 要求

在 Android P 中,您不能从非 Activity 环境中启动 Activity,除非您传递 Intent 标志 FLAG_ACTIVITY_NEW_TASK。 如果您尝试在不传递此标志的情况下启动 Activity,则该 Activity 不会启动,系统会在日志中输出一则消息。

注:在 Android N 之前,标志要求一直是期望的行为并被强制执行。 Android N 中的一个错误会临时阻止实施标志要求。

屏幕旋转变更

Android O 中的用户可以使用 Quicksettings 图块或 Display 设置在自动屏幕旋转纵向旋转模式之间切换。 Android P 对纵向旋转模式做出了重大变更。 纵向模式已重命名为旋转锁定,它会在自动屏幕旋转关闭时启用。 自动屏幕旋转模式没有任何变更。

当设备处于旋转锁定模式时,用户可将其屏幕锁定到顶层可见 Activity 所支持的任何旋转。 Activity 不应假定它将始终以纵向呈现。 如果顶层 Activity 可在自动屏幕旋转模式下以多种旋转呈现,则应在旋转锁定模式下提供相同的选项,根据 Activity 的 screenOrientation 设置,允许存在一些例外情况(见下表)。

请求特定屏幕方向(例如,screenOrientation=landscape)的 Activity 会忽略用户锁定首选项,并且行为与 Android O 中的行为相同。

可在 Android 清单中,或以编程方式通过 setRequestedOrientation(),在 Activity 一级设置屏幕方向首选项。

旋转锁定模式通过设置 WindowManager 在处理 Activity 旋转时使用的用户旋转首选项来发挥作用。 用户旋转首选项可能在下列情况下发生变更。 请注意,恢复纵向模式存在偏差:

  • 当用户接受旋转建议时,旋转首选项变为建议方向。
  • 当用户切换到强制纵向应用(包括锁定屏幕或启动器)时,旋转首选项变为纵向。

下表总结了常见屏幕方向的旋转行为:

屏幕方向 行为
未指定、user 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。
userLandscape 在自动屏幕旋转和旋转锁定下,Activity 可以横向或颠倒横向呈现。 预期只支持横向布局。
userPortrait 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或颠倒纵向呈现。 预期只支持纵向布局。
fullUser 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。

旋转锁定用户将可选择锁定到颠倒纵向,通常为 180º。
sensor、fullSensor、sensorPortrait、sensorLandscape 忽略旋转锁定模式首选项,视为自动屏幕旋转已启用。 请仅在例外情况下并经过仔细的用户体验考量后再使用此项。

针对 Android P 的应用

这些行为变更仅应用于针对 P 平台或更高版本的应用。 针对 Android P 或更高版本进行编译,或将 targetSdkVersion 设为 Android P 或更高版本的应用开发者必须修改其应用以正确支持这些行为(如果适用)。

前台服务

针对 Android P 或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限。 这是普通权限,因此,系统会自动为请求权限的应用授予此权限。

如果针对 Android P 的应用尝试创建一个前台服务且未请求 FOREGROUND_SERVICE,则系统会引发 SecurityException

设备串行访问限制

Build.SERIAL 字段在 Android 8.0(API 级别 26)中已被弃用。 在 Android P 中,Build.SERIAL 始终设置为 "UNKNOWN"。 此变更旨在保护用户的隐私。

如果您的应用需要访问设备的硬件序列号,您应请求 READ_PHONE_STATE 权限,然后调用 getSerial()

框架安全性变更

如果您的应用以 Android P 为目标平台,则系统会执行更严格的网络和文件系统安全保障。 如需了解更多详情,请参阅安全行为变更页面上对以 Android P 为目标平台的应用做出的变更。

视图焦点

0 面积的视图(即宽度或高度为 0)再也不能被聚焦。

此外,Activity 不再隐式分配触摸模式下的初始焦点, 而是由您显式请求初始焦点(如若需要的话)。

Android P 应用支持草案版 CSS 颜色模块级别 4的行为,用于处理 4 和 8 个十六进制数字 CSS 颜色。

Chrome 自版本 52 以来便一直支持 CSS 颜色模块级别 4,但 WebView 目前停用此功能,因为现有 Android 应用被发现包含 Android ordering (ARGB) 中的 32 位十六进制颜色,这会导致渲染错误。

例如,对于以 Android P 之前的 SDK 为目标的应用,颜色 #80ff8080 目前在 WebView 中被渲染为不透明浅红色 (#ff8080)。 先导部分(Android 会将其解读为 Alpha 部分)目前被忽略。 如果某个应用以 P 或更高版本为目标,则它将被解读为 50% 透明浅绿 (#80ff80)。

文档滚动标签

在 Android P 之前的版本中,滚动位置在 body 元素上设置,根元素的滚动值为零。 Android P 支持符合标准的行为,在这种行为中,滚动元素根元素。

此外,直接访问 document.body.scrollTopdocument.body.scrollLeftdocument.documentElement.scrollTopdocument.documentElement.scrollLeft 会因目标 SDK 的不同而具有不同的行为。 要访问视口滚动值,请使用 document.scrollingElement(若有)。