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) 的距离。设备必须已启用位置信息服务并开启 WLAN 扫描(在设置 > 位置信息下),并且您的应用必须具有 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 内置了对 High Dynamic Range (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,增加了对 9 种新运算的支持:

已知问题:将 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 的支持。此方案可以选择在每个签名证书的签名分块中包含一条轮转证明记录。借助此功能,您可以将 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。

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

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