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 API 测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 的距离。设备必须启用位置信息服务并开启 Wi-Fi 扫描(在设置 > 位置信息下),并且您的应用必须具有 ACCESS_FINE_LOCATION 权限。设备无需连接到接入点即可使用 RTT。为了保护隐私,只有手机可以确定与接入点的距离;接入点无此信息。

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

通过这种方式,您可以打造新的体验,例如建筑物内导航和基于位置的精细服务,例如无歧义的语音控制(例如“打开这盏灯”)和基于位置的信息(例如“此产品是否有特别优惠?”)。

请参阅 Android WifiRttScan 演示版应用中的 Wi-Fi RTT API。

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

刘海屏支持

显示各种刘海屏尺寸的开发者选项界面

使用模拟器测试刘海屏

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 共享(可让相机客户端无需停止和启动相机流式传输即可处理各种用例)。我们还添加了相关 API,用于实现基于显示屏的闪光灯支持以及访问 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,它是 AnimatedImageDrawable 类的一个实例。

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

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

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

动画

Android 9 引入了 AnimatedImageDrawable 类,用于绘制和显示 GIF 和 WebP 动画图片。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 图片压缩和 Media 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

Android 8.1(API 级别 27)中引入了 Neural Networks API,以加快 Android 上的设备端机器学习。Android 9 扩展并改进了该 API,添加了对以下九种新运算的支持:

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

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

自动填充框架

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

安全增强功能

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

Android Protected Confirmation

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

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

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

如需有关添加对 Android 受保护的确认的支持的指南,请参阅 Android 受保护的确认指南。

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

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

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

硬件安全模块

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

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

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

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

保护对密钥库进行的密钥导入

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

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

具有密钥轮替的 APK 签名方案

Android 9 增加了对 APK 签名方案 v3 的支持。使用此方案时,可以选择在每个签名证书的签名分块中添加 proof-of-rotation 记录。借助此功能,您可以将 APK 文件过去的签名证书与现在用于签名的证书相关联,从而使用新的签名证书为应用签名。

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

用于仅允许在未锁定设备上进行密钥解密的选项

Android 9 引入了 unlockedDeviceRequired 标志。此选项确定在允许使用指定密钥解密任何传输中的数据或存储的数据之前,密钥库是否要求解锁屏幕。这些类型的密钥非常适合用于加密要存储在磁盘上的敏感数据,例如健康数据或企业数据。该标志为用户提供了更高的保证,即使手机丢失或被盗,在设备锁定时无法解密数据。

为了确保在设备锁定时密钥的安全解密,请将 true 传递给 setUnlockedDeviceRequired() 方法来启用该标志。完成此步骤后,当用户的屏幕处于锁定状态时,任何尝试使用此密钥解密或签署数据的操作都将失败。锁定的设备必须输入 PIN 码、密码、指纹或其他一些可信因素才能访问。

旧版加密支持

附带 Keymaster 4 的 Android 9 设备支持三重数据加密算法(简称三重 DES)。如果您的应用与需要三重 DES 的旧版系统进行互操作,请在加密敏感凭据时使用这种加密方式。

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

弃用 WPS

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

Android 备份

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

客户端加密备份

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

启用此隐私保护措施后,必须使用设备的 PIN 码、图案或密码才能从用户设备制作的备份中恢复数据。如需详细了解此功能背后的技术,请参阅 Google Cloud 密钥保险柜服务白皮书。

定义备份所需的设备条件

如果您的应用数据包含敏感信息或偏好设置,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 属性来确定何时应将 ViewGroupView 对象的集合作为一个单元进行读取。这样,用户就可以了解这些视图在逻辑上彼此相关。

在 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 类是一个提供放大镜 API 的平台 widget,可在所有应用中提供一致的放大镜功能体验。

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

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

DEX 文件的 ART 提前转换

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

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

设备端系统跟踪

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

通过收集这些跟踪记录,您可以捕获与应用的进程和线程相关的时间数据,并查看其他类型的具有全局显著性的设备状态。

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