Android 9 功能和 API

Android 9(API 级别 28)为用户和开发者引入了一些出色的新功能。本文重点介绍面向开发者的新功能。

如需了解新 API,请阅读 API 差异报告或访问 Android API 参考文档。此外,请务必查看 Android 9 行为变更,了解平台变更可能会在哪些方面影响您的应用。

使用 Wi-Fi RTT 进行室内定位

新的 RTT API 支持在应用中进行室内定位。

Android 9 新增了对 IEEE 802.11-2016 Wi-Fi 协议(也称为 Wi-Fi 往返时间 [RTT])的平台支持,以便您在应用中利用室内定位功能。

在运行 Android 9 且支持 RTT 的设备上,您的应用可以使用 RTT API 测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 之间的距离。设备必须启用位置信息服务并打开 WLAN 扫描(位于设置 > 位置信息下),并且您的应用必须具有 ACCESS_FINE_LOCATION 权限。设备无需连接到接入点即可使用 RTT。 为了保护隐私,只有手机能够确定距接入点的距离,接入点没有此类信息。

如果设备测量与 3 个或更多接入点的距离,您可以使用多点定位算法来预估与这些测量值最相符的设备位置。结果通常精准至 1 至 2 米。

凭借这种精准度,您可以打造全新体验,例如楼内导航和基于精确位置的服务,例如无歧义语音控制(例如,“打开这盏灯”)以及基于位置的信息(例如,“此产品是否有特别优惠?”)。

您可以在 Android WifiRttScan 演示应用中查看 WiFi RTT API 的使用情况。

如需了解详情,请参阅通过 RTT 确定 Wi-Fi 位置信息

刘海屏支持

“开发者选项”界面,显示了不同的刘海屏尺寸

使用模拟器测试刘海屏

Android 9 支持最新的无边框屏幕,这些屏幕包含用于摄像头和扬声器的刘海屏。借助 DisplayCutout 类,您可以了解不应显示内容的不起作用区域的位置和形状。如需确定这些刘海区域的存在情况和放置位置,请使用 getDisplayCutout() 方法。

借助新的窗口布局属性 layoutInDisplayCutoutMode,应用可以围绕设备的刘海屏布局其内容。您可以将此属性设置为以下某个值:

您可以在搭载 Android 9 的任意设备或模拟器上模拟刘海屏,具体操作步骤如下:

  1. 启用开发者选项
  2. 开发者选项界面中,向下滚动到绘制部分,然后选择模拟刘海屏
  3. 选择刘海屏的大小。

通知

Android 9 对通知进行了多项增强,所有这些增强功能都适用于以 API 级别 28 及更高级别为目标的开发者。

消息通知

附加了照片的 MessagingStyle。

即时通讯通知

包含回复和对话的 MessagingStyle。

如需查看使用通知(包括 Android 9 中的功能)的示例代码,请参阅人员示例

增强的消息传递体验

从 Android 7.0(API 级别 24)开始,您可以添加直接在通知中回复消息或输入其他文字的操作。Android 9 通过以下增强功能改进了此功能:

  • 简化了对对话参与者的支持:Person 类用于标识对话中涉及的人员,包括其头像和 URI。许多其他 API(例如 addMessage())现在都利用 Person 类,而不是 CharSequencePerson 类还支持构建器设计模式。

  • 支持图片:Android 9 现在可在手机上的即时通讯通知中显示图片。您可以在消息中使用 setData() 来显示图片。以下代码段演示了如何创建 Person 和包含图片的消息。

Kotlin

// Create new Person.
val sender = Person()
        .setName(name)
        .setUri(uri)
        .setIcon(null)
        .build()
// Create image message.
val message = Message("Picture", time, sender)
        .setData("image/", imageUri)
val style = Notification.MessagingStyle(getUser())
        .addMessage("Check this out!", 0, sender)
        .addMessage(message)

Java

// Create new Person.
Person sender = new Person()
        .setName(name)
        .setUri(uri)
        .setIcon(null)
        .build();
// Create image message.
Message message = new Message("Picture", time, sender)
        .setData("image/", imageUri);
Notification.MessagingStyle style = new Notification.MessagingStyle(getUser())
        .addMessage("Check this out!", 0, sender)
        .addMessage(message);
  • 将回复保存为草稿:当用户意外关闭消息通知时,您的应用可以检索系统发送的 EXTRA_REMOTE_INPUT_DRAFT。您可以使用此 extra 预填充应用中的文本字段,以便用户完成回复。

  • 确定对话是否为群组对话:您可以使用 setGroupConversation() 有目的地将对话标识为群组对话或非群组对话。

  • 为 intent 设置语义操作:借助 setSemanticAction() 方法,您可以为操作赋予语义含义,例如“标记为已读”“删除”“回复”等。

  • SmartReply:Android 9 支持与消息应用中相同的建议回复。使用 RemoteInput.setChoices() 可向用户提供一系列标准回复。

频道设置、广播和“勿扰”

Android 8.0 引入了通知渠道,让您可以为要显示的每种类型的通知创建一个可供用户自定义的渠道。Android 9 通过下列变更简化通知渠道设置:

多摄像头支持和摄像头更新

在搭载 Android 9 的设备上,您可以同时访问来自两个或更多个物理摄像头的数据流。在配备双前置或双后置摄像头的设备上,您可以创建仅使用单个摄像头无法实现的创新功能,例如无缝变焦、散景和立体视觉。该 API 还允许您调用逻辑或融合摄像头数据流,该数据流可在两个或更多个摄像头之间自动切换。

相机方面的其他改进包括:新增了会话参数,有助于减少初始捕获期间的延迟;新增了 Surface 共享,让相机客户端无需停止和启动相机流式传输即可处理各种用例。我们还添加了基于显示屏的闪光灯支持和对 OIS 时间戳的访问权限,以实现应用级图像稳定和特效。

在 Android 9 中,多摄像头 API 支持具有 FULLLIMITED 功能的设备的单色摄像头。单色输出通过 YUV_420_888 格式实现,其中 Y 为灰度,U (Cb) 为 128,V (Cr) 为 128。

Android 9 还可在支持的设备上支持外部 USB/UVC 相机

适用于可绘制对象和位图的 ImageDecoder

Android 9 引入了 ImageDecoder 类,该类提供了一种现代化的图片解码方法。请使用此类,而不要使用 BitmapFactoryBitmapFactory.Options API。

借助 ImageDecoder,您可以从字节缓冲区、文件或 URI 创建 DrawableBitmap。如需解码图片,请先使用编码图片的来源调用 createSource()。然后,通过传递 ImageDecoder.Source 对象来调用 decodeDrawable()decodeBitmap(),以创建 DrawableBitmap。如需更改默认设置,请将 OnHeaderDecodedListener 传递给 decodeDrawable()decodeBitmap()ImageDecoder 会在知道图片的默认宽度和高度后,调用 onHeaderDecoded()。如果编码后的图片是动画 GIF 或 WebP,decodeDrawable() 会返回一个 Drawable,该 DrawableAnimatedImageDrawable 类的实例。

您可以使用不同的方法来设置图像属性:

  • 如需将解码后的图片缩放到确切的大小,请将目标尺寸传递给 setTargetSize()。您还可以使用样本大小来缩放图片。将样本大小直接传递给 setTargetSampleSize()
  • 如需在缩放后的图片范围内裁剪图片,请调用 setCrop()
  • 如需创建可变位图,请将 true 传递到 setMutableRequired()

ImageDecoder 还可让您为图片添加自定义的复杂效果,例如圆角或圆形遮罩。将 setPostProcessor()PostProcessor 类的实例搭配使用,以执行所需的任何绘制命令。

动画

Android 9 引入了用于绘制和显示 GIF 及 WebP 动画图片的 AnimatedImageDrawable 类。AnimatedImageDrawable 的工作方式与 AnimatedVectorDrawable 类似,都是由渲染线程驱动 AnimatedImageDrawable 的动画。渲染线程还使用工作线程进行解码,这样解码就不会干扰渲染线程上的其他操作。此实现可让您的应用显示动画图片,而无需管理其更新或干扰应用界面线程上的其他事件。

可以使用 ImageDecoder 的实例对 AnimatedImageDrawable 进行解码。以下代码段展示了如何使用 ImageDecoder 解码 AnimatedImageDrawable

Kotlin

@Throws(IOException::class)
private fun decodeImage() {
    val decodedAnimation = ImageDecoder.decodeDrawable(
        ImageDecoder.createSource(resources, R.drawable.my_drawable))

    // Prior to start(), the first frame is displayed.
    (decodedAnimation as? AnimatedImageDrawable)?.start()
}

Java

private void decodeImage() throws IOException {
    Drawable decodedAnimation = ImageDecoder.decodeDrawable(
        ImageDecoder.createSource(getResources(), R.drawable.my_drawable));

    if (decodedAnimation instanceof AnimatedImageDrawable) {
        // Prior to start(), the first frame is displayed.
        ((AnimatedImageDrawable) decodedAnimation).start();
    }
}

ImageDecoder 有多种方法可让您进一步修改图片。例如,您可以使用 setPostProcessor() 方法修改图片的外观,例如应用圆形遮罩或圆角。

HDR VP9 视频、HEIF 图片压缩和媒体 API

Android 9 内置了对高动态范围 (HDR) VP9 Profile 2 的支持,因此您可以在支持 HDR 的设备上通过 YouTube、Play 电影和其他来源向用户提供支持 HDR 的影片。

Android 9 还添加了对使用高效图片文件格式 (HEIF 或 HEIC) 编码图片的支持,从而可提高压缩率并减少存储空间和网络数据使用量。MediaMuxerMediaExtractor 类支持 HEIF 静态图片示例。借助 Android 9 设备上的平台支持,您可以轻松地从后端服务器发送和使用 HEIF 图片。确保应用兼容此数据格式以进行分享和显示后,您可以尝试将 HEIF 用作应用中的图片存储格式。您可以使用 ImageDecoderBitmapFactory(从 JPEG 文件获取位图)将 JPEG 转换为 HEIC。然后,您可以使用 HeifWriter 从 YUV 字节缓冲区或 SurfaceBitmap 的实例写入 HEIF 静止图像。

您还可以通过 AudioTrackAudioRecordMediaDrm 类获取媒体指标。

Android 9 引入了 MediaDRM 类的方法,用于获取指标、HDCP 级别、安全级别和会话数,并可更好地控制安全级别和安全停止。如需了解详情,请参阅 API 差异报告

在 Android 9 中,AAudio API 增加了对多个额外 AAudioStream 属性的支持,包括用途、内容类型和输入预设。使用这些属性,您可以创建针对 VoIP 或摄像机应用调整的流。您还可以设置会话 ID,以将 AAudio 流与可包含效果的子混音相关联。使用 AudioEffect API 控制效果。

Android 9 引入了用于动态处理AudioEffect API。借助此类,您可以在多个阶段构建基于声道的音频效果,包括均衡、多频段压缩和限制器。频段和活跃阶段的数量可配置,并且大多数参数都可以实时控制。

JobScheduler 中的数据流量费用敏感度

从 Android 9 开始,JobScheduler 可以使用运营商提供的网络状态信号来改进与网络相关的作业的处理。

作业可以声明其估计的数据大小、发出预提取信号,并指定详细的网络要求。然后,JobScheduler 会根据网络状态管理工作。例如,当网络发出拥塞信号时,JobScheduler 可能会延迟处理大型网络请求。在非按流量计费的网络上,JobScheduler 可以运行预提取作业来改善用户体验,例如预提取新闻标题。

添加作业时,请务必在适当的时候使用 setEstimatedNetworkBytes()setPrefetch()setRequiredNetwork(),以帮助 JobScheduler 正确处理工作。作业执行时,请务必使用 JobParameters.getNetwork() 返回的 Network 对象。否则,您将隐式使用设备的默认网络,而该网络可能无法满足您的要求,从而导致意外的数据使用。

Neural Networks API 1.1

Neural Networks API 于 Android 8.1(API 级别 27)中引入,旨在加速 Android 设备上的设备端机器学习。Android 9 扩展并改进了该 API,新增了对以下九种操作的支持:

已知问题:将 ANEURALNETWORKS_TENSOR_QUANT8_ASYMM 张量传递给 Android 9 及更高版本中提供的 ANEURALNETWORKS_PAD 运算时,NNAPI 的输出可能与更高层级机器学习框架(如 TensorFlow Lite)的输出不匹配。在问题得到解决之前,您应该改为只传递 ANEURALNETWORKS_TENSOR_FLOAT32

此外,该 API 还引入了一个新函数 ANeuralNetworksModel_relaxComputationFloat32toFloat16(),可用于指定是否以 IEEE 754 16 位浮点格式的范围和精度来计算 ANEURALNETWORKS_TENSOR_FLOAT32

自动填充框架

Android 9 引入了多项改进,自动填充服务可以实现这些改进,以便在填写表单时进一步提升用户体验。如需详细了解如何在应用中使用自动填充功能,请参阅自动填充框架指南。

安全增强功能

Android 9 引入了若干安全功能,详见以下各节摘要说明:

Android Protected Confirmation

在搭载 Android 9 或更高版本的受支持设备上,您可以使用 Android 受保护的确认功能。使用此工作流时,应用会向用户显示提示,请他们批准一个简短的声明。应用可以通过这个声明再次确认,用户确实想完成一项敏感交易(例如付款)。

如果用户接受该声明,Android 密钥库会接收并存储受密钥哈希消息身份验证码 (HMAC) 保护的加密签名。在 Android 密钥库确认消息的有效性后,您的应用可以使用在可信执行环境 (TEE) 中从 trustedConfirmationRequired 生成的密钥对用户接受的消息进行签名。该签名具有很高的可信度,表示用户已看过声明并同意其内容。

注意:Android 受保护的确认并非为用户提供安全信息通道。应用不能假定存在 Android 平台所提供机密性保证之外的任何其他保证。具体而言,请勿使用该工作流显示您通常不会在用户设备上显示的敏感信息。

如需有关添加对 Android Protected Confirmation 的支持的指南,请参阅 Android Protected Confirmation 指南。

统一的生物识别身份验证对话框

在 Android 9 中,系统会代表您的应用提供生物识别身份验证对话框。此功能可为对话框创建标准化的外观、风格和放置位置,让用户更有信心,他们正在针对可信的生物识别凭据检查器进行身份验证。

如果您的应用使用 FingerprintManager 向用户显示指纹身份验证对话框,请改为使用 BiometricPromptBiometricPrompt 依赖于系统来显示身份验证对话框。它还会改变自身行为,以适应用户选择的生物识别验证类型。

硬件安全模块

运行 Android 9 或更高版本的受支持设备可拥有 StrongBox KeyMint(以前称为 Keymaster),它是位于硬件安全模块中的 KeyMint(以前称为 Keymaster)HAL 的一种实现。该模块包含以下组成部分:

  • 自己的 CPU。
  • 安全存储空间。
  • 真实随机数生成器。
  • 可抵御软件包篡改和未经授权旁加载应用的附加机制。

检查存储在 StrongBox KeyMint 中的密钥时,系统会通过可信执行环境 (TEE) 证实密钥的完整性。

如需详细了解如何使用 StrongBox KeyMint,请参阅硬件安全模块

将密钥安全导入密钥库

Android 9 增加了使用 ASN.1 编码密钥格式将已加密密钥安全导入密钥库的功能,从而提高了密钥解密的安全性。KeyMint 随后会在密钥库中将密钥解密,因此密钥的内容永远不会以明文形式出现在设备的主机内存中。

详细了解如何更安全地导入加密密钥

支持密钥轮换的 APK 签名方案

Android 9 新增了对 APK 签名方案 v3 的支持。此方案可以选择在每个签名证书的签名块中包含 proof-of-rotation 记录。此功能通过将 APK 文件的过往签名证书与当前使用的签名证书相关联,使您的应用能够使用新的签名证书进行签名。

详细了解如何使用 apksigner 轮替密钥。

允许仅在设备解锁时进行密钥解密的选项

Android 9 引入了 unlockedDeviceRequired 标志。此选项用于确定密钥库是否要求先解锁屏幕,然后才能使用指定密钥解密任何传输中或存储的数据。这类密钥非常适合用于加密要存储在磁盘上的敏感数据,例如健康数据或企业数据。此标志可让用户更放心地相信,即使手机丢失或被盗,数据在设备锁定时也无法被解密。

如需在设备处于锁定状态时确保密钥免遭解密,请通过向 setUnlockedDeviceRequired() 方法传递 true 来启用相应标志。完成此步骤后,当用户锁定屏幕时,任何尝试使用此密钥解密或签名数据的操作都会失败。锁定状态的设备需要 PIN 码、密码、指纹或某些其他可信因素才能访问。

旧版加密支持

搭载 Keymaster 4 的 Android 9 设备支持三重数据加密算法 (Triple Data Encryption Algorithm),即 Triple DES。如果您的应用与需要 Triple DES 的旧版系统互操作,请在加密敏感凭据时使用此类加密。

如需详细了解如何提高应用的安全性,请参阅 Android 开发者安全性

弃用 WPS

出于安全考虑,WLAN 保护设置 (WPS) 已被弃用。

Android 备份

Android 9 添加了与备份和恢复相关的新功能和开发者选项。有关这些变更的详细信息,请参阅以下各部分。

客户端加密功能备份

Android 9 新增了对使用客户端密钥加密 Android 备份的支持。满足以下条件时,系统会自动启用此支持:

启用此隐私保护措施后,用户需要输入设备的 PIN 码、解锁图案或密码,才能从用户设备创建的备份中恢复数据。如需详细了解此功能背后的技术,请参阅 Google Cloud Key Vault Service 白皮书。

定义备份所需的设备条件

如果您的应用数据包含敏感信息或偏好设置,Android 9 可让您定义设备条件,以便在满足这些条件时将应用数据纳入用户备份中,例如在启用客户端加密或进行本地设备到设备传输时。

如需详细了解如何在 Android 设备上备份数据,请参阅数据备份概览

无障碍

Android 9 对无障碍功能框架进行了增强,让您可以更轻松地为应用用户提供更出色的体验。

导航语义

Android 9 中添加的属性可让您更轻松地定义无障碍服务(尤其是屏幕阅读器)从屏幕的一部分导航到另一部分的方式。这些属性可帮助有视觉障碍的用户快速浏览应用界面中的文字,并允许他们进行选择。

例如,在购物应用中,屏幕阅读器可以帮助用户直接从一个类别的优惠导航到下一个类别的优惠,而无需屏幕阅读器先读完某个类别中的所有商品,然后再继续读下一个类别。

无障碍窗格标题

在 Android 8.1(API 级别 27)及更低版本中,无障碍服务无法始终确定屏幕的特定窗格何时更新,例如当 activity 用一个 fragment 替换另一个 fragment 时。窗格由逻辑分组的、在视觉上相关的界面元素组成,通常包含一个 fragment。

在 Android 9 中,您可以为这些窗格提供无障碍窗格标题或可单独识别的标题。如果窗格具有无障碍窗格标题,则当窗格发生变化时,无障碍服务会收到更详细的信息。 此功能可让服务向用户提供有关界面中发生的变化的更精细信息。

如需指定窗格的标题,请使用 android:accessibilityPaneTitle 属性。您还可以使用 setAccessibilityPaneTitle() 更新在运行时替换的界面窗格的标题。例如,您可以为 Fragment 对象的内容区域提供标题。

基于航向的导航

如果您的应用显示的文字内容包含逻辑标题,请将表示这些标题的 View 实例的 android:accessibilityHeading 属性设置为 true。添加这些标题后,无障碍服务便可帮助用户直接从一个标题导航到下一个标题。任何无障碍服务都可以使用此功能来改善用户的界面导航体验。

群组导航和输出

屏幕阅读器传统上使用 android:focusable 属性来确定何时应将 ViewGroup 或一组 View 对象作为单个单元进行朗读。这样,用户就可以了解这些视图在逻辑上是相互关联的。

在 Android 8.1 及更低版本中,您需要将 ViewGroup 中的每个 View 对象标记为不可聚焦,并将 ViewGroup 本身标记为可聚焦。这种安排导致某些 View 实例被标记为可聚焦,从而使键盘导航更加繁琐。

从 Android 9 开始,在使 View 对象可聚焦会产生不良后果的情况下,您可以使用 android:screenReaderFocusable 属性来代替 android:focusable 属性。屏幕阅读器会将焦点放在已将 android:screenReaderFocusableandroid:focusable 设置为 true 的所有元素上。

便捷操作

Android 9 新增了一些方便用户执行操作的支持功能:

与提示互动
无障碍框架中添加的功能可让您访问应用界面中的提示。使用 getTooltipText() 可读出提示的文字,而使用 ACTION_SHOW_TOOLTIPACTION_HIDE_TOOLTIP 可指示 View 的实例显示或隐藏它们的提示。
添加了全局操作
Android 9 在 AccessibilityService 类中引入了对另外两项设备操作的支持。您的服务可以帮助用户分别使用 GLOBAL_ACTION_LOCK_SCREENGLOBAL_ACTION_TAKE_SCREENSHOT 操作锁定设备和拍摄屏幕截图。

窗口更改详细信息

Android 9 使得在应用同时重新绘制多个窗口时,可以更轻松地跟踪应用窗口的更新。发生 TYPE_WINDOWS_CHANGED 事件时,应使用 getWindowChanges() API 来确定窗口是如何更改的。在多窗口更新期间,每个窗口都会生成一系列自己的事件。 getSource() 方法会返回与每个事件关联的窗口的根视图。

如果某个应用为其 View 对象定义了无障碍窗格标题,那么当该应用的界面更新时,服务就能分辨出来。发生 TYPE_WINDOW_STATE_CHANGED 事件时,应使用 getContentChangeTypes() 返回的类型来确定窗口是如何更改的。例如,当窗格有了新标题或者窗格消失时,框架可以检测到。

旋转

为避免发生意外旋转,我们添加了一种模式,即使设备位置发生变化,也能固定当前屏幕方向。用户可以根据需要手动触发旋转,只需按一下系统栏中的按钮即可。

在大多数情况下,对应用的兼容性影响很小。不过,如果您的应用有任何自定义的旋转行为或使用任何不寻常的屏幕方向设置,您可能会遇到之前未曾注意到的问题,因为之前用户旋转偏好设置始终设置为竖屏。我们建议您查看应用中所有关键 activity 的旋转行为,并确保所有屏幕方向设置仍能提供最佳体验。

如需了解详情,请参阅相关的行为变更

旋转移动设备,显示新的旋转模式,让用户手动触发旋转

借助新的旋转模式,用户可以根据需要使用系统栏中的按钮手动触发旋转。

文本

Android 9 为平台带来了以下与文本相关的功能:

  • 预计算文本:PrecomputedText 类可让您提前计算并缓存所需的信息,从而提高文本渲染性能。它还使您的应用能够在主线程之外执行文本布局。

  • 放大镜:Magnifier 类是一个平台 widget,提供放大镜 API,可在所有应用中提供一致的放大镜功能体验。

  • 智能 Linkify:Android 9 增强了 TextClassifier 类,该类利用机器学习技术来识别所选文本中的某些实体并建议操作。例如,TextClassifier 可让您的应用检测到用户已选择电话号码。然后,您的应用可以建议用户使用该号码拨打电话。TextClassifier 中的功能取代了 Linkify 类的功能。

  • 文本布局:多种便捷方法和属性可让您更轻松地实现界面设计。如需了解详情,请参阅 TextView 的参考文档。

ART 对 DEX 文件进行预先转换

在搭载 Android 9 或更高版本的设备上,Android 运行时 (ART) 预先 (AOT) 编译器会通过将应用软件包中的 DEX 文件转换为更紧凑的表示形式,进一步优化压缩的 Dalvik 可执行格式 (DEX) 文件。此变更可让您的应用更快地启动,并占用更少的磁盘空间和 RAM。

此改进尤其有利于磁盘 I/O 速度较慢的低端设备。

设备端系统跟踪

Android 9 允许您从设备中记录系统轨迹,然后与开发团队分享这些记录的报告。此报告支持多种格式,包括 HTML。

通过收集这些轨迹,您可以捕获与应用进程和线程相关的时间数据,并查看其他类型的全局重要设备状态。

如需详细了解此工具,请参阅执行设备端系统跟踪