优化助理的上下文内容

Android 6.0 Marshmallow 引入了一种新方式,让用户可以通过助理应用(例如 Google Assistant)与应用进行互动。助理是一个顶层窗口,用户可以查看该窗口,以获取与当前 Activity 上下文相关的操作。这些操作可能包括指向设备上其他应用的深层链接。

用户长按主屏幕按钮或说出热词即可激活助理。系统会随之打开一个顶层窗口,其中显示上下文相关的操作。

助理应用(例如 Google Assistant)通过一项称为 Now on Tap 的功能实现助理叠加窗口,该功能与 Android 平台级功能配合使用。系统允许用户选择助理应用,该应用使用 Android 的 Assist API 从您的应用中获取上下文信息。

本指南介绍了 Android 应用如何使用 Android 的 Assist API 来改善助理的用户体验。要了解如何创建媒体应用以便助理可以启动和控制,请参阅Google Assistant 和媒体应用

使用助理

图 1 说明了用户与助理进行典型互动。当用户长按主屏幕按钮时,会在应用中调用 Assist API 回调(步骤 1)。助理渲染叠加窗口(步骤 2 和 3),然后用户选择要执行的操作。助理执行所选操作,例如使用深层链接向(目标)餐厅应用发送 Intent(步骤 4)。

图 1. 使用 Google App 的 Now on Tap 功能的助理互动示例

用户可以通过选择 设置 > 应用 > 默认应用 > 助理与语音输入来配置助理。用户可以更改系统选项,例如以文本形式访问屏幕内容和访问屏幕截图,如图 2 所示。

图 2. 助理与语音输入设置

源应用

为了确保您的应用可以作为助理获取用户信息的来源,您只需遵循无障碍功能最佳实践即可。本部分介绍了如何提供其他信息以帮助改善助理的用户体验,以及需要特殊处理的场景,例如自定义 View。

与助理分享其他信息

除了文本和屏幕截图外,您的应用还可以与助理分享其他信息。例如,您的音乐应用可以选择传递当前专辑信息,以便助理可以建议更智能、更适合当前 Activity 的操作。请注意,Assist API 不提供媒体控件。要添加媒体控件,请参阅Google Assistant 和媒体应用

要向助理提供其他信息,您的应用可以通过注册应用监听器提供全局应用上下文,并通过 Activity 回调提供 Activity 特定的信息,如图 3 所示。

图 3. Assist API 生命周期序列图

要提供全局应用上下文,应用会创建 Application.OnProvideAssistDataListener 的实现,并使用 registerOnProvideAssistDataListener() 进行注册。要提供 Activity 特定的上下文信息,Activity 会重写 onProvideAssistData()onProvideAssistContent()。这两个 Activity 方法会在可选的全局回调调用之后调用。由于回调在主线程上执行,因此应尽快完成。回调仅在 Activity 运行时调用。

提供上下文

当用户激活助理时,会调用 onProvideAssistData() 来构建完整的 ACTION_ASSIST Intent,其中包含表示为 AssistStructure 实例的当前应用的所有上下文。您可以重写此方法,将您想要的任何内容放入 bundle 中,以便显示在 assist intent 的 EXTRA_ASSIST_CONTEXT 部分。

描述内容

您的应用可以实现 onProvideAssistContent(),通过提供与当前 Activity 相关的内容引用来改善助理的用户体验。您可以使用 Schema.org 定义的通用词汇表,通过 JSON-LD 对象来描述应用内容。在以下示例中,一个音乐应用提供了结构化数据来描述用户当前正在查看的音乐专辑

Kotlin

override fun onProvideAssistContent(assistContent: AssistContent) {
    super.onProvideAssistContent(assistContent)

    val structuredJson: String = JSONObject()
            .put("@type", "MusicRecording")
            .put("@id", "https://example.com/music/recording")
            .put("name", "Album Title")
            .toString()

    assistContent.structuredData = structuredJson
}

Java

@Override
public void onProvideAssistContent(AssistContent assistContent) {
  super.onProvideAssistContent(assistContent);

  String structuredJson = new JSONObject()
       .put("@type", "MusicRecording")
       .put("@id", "https://example.com/music/recording")
       .put("name", "Album Title")
       .toString();

  assistContent.setStructuredData(structuredJson);
}

您还可以通过 onProvideAssistContent() 的自定义实现来改善用户体验,这可以带来以下好处:

注意:使用自定义文本选择实现的应用可能需要实现 onProvideAssistContent() 并调用 setClipData()

默认实现

如果未实现 onProvideAssistData()onProvideAssistContent() 回调,系统仍然会继续并将自动收集的信息传递给助理,除非当前窗口已标记为安全。如图 3 所示,系统使用 onProvideStructure()onProvideVirtualStructure() 的默认实现来收集文本和视图层次结构信息。如果您的视图实现自定义文本绘制,请重写 onProvideStructure() 以通过调用 setText(CharSequence) 为助理提供向用户显示的文本。

大多数情况下,实现无障碍支持使助手能够获取所需信息。要实现无障碍支持,请遵循使应用可访问中介绍的最佳实践,包括以下内容

从助理中排除视图

为处理敏感信息,您的应用可以通过设置 WindowManagerFLAG_SECURE 布局参数,将当前视图从助理中排除。对于 Activity 创建的每个窗口(包括对话框),您都必须显式设置 FLAG_SECURE。您的应用还可以使用 setSecure() 将 Surface 从助理中排除。没有全局(应用级)机制来将所有视图从助理中排除。请注意,FLAG_SECURE 不会导致 Assist API 回调停止触发。使用 FLAG_SECURE 的 Activity 仍然可以使用本指南前面描述的回调,显式地向助理应用提供信息。

注意:对于企业帐号(Android for Work),管理员可以使用 DevicePolicyManager API 的 setScreenCaptureDisabled() 方法,为工作资料禁用助理数据的收集功能。

语音互动

在检测到热词时,也会调用 Assist API 回调。如需了解详情,请参阅语音操作文档。

Z 轴顺序注意事项

助理使用一个轻量级叠加窗口,显示在当前 Activity 的顶部。由于用户可以随时激活助理,因此请勿创建永久性的系统提醒窗口来干扰叠加窗口,如图 4 所示。

图 4. 助理层的 Z 轴顺序

如果您的应用使用系统提醒窗口,请及时移除它们,因为将它们留在屏幕上会降低用户体验。

目标应用

助理应用通常利用深层链接来查找目标应用。为了使您的应用成为潜在的目标应用,请考虑添加深层链接支持。当前用户上下文与叠加窗口中显示的深层链接或其他潜在操作(如图 1 的步骤 3 所示)之间的匹配特定于 Google Assistant 的实现方式。例如,Google Assistant 应用使用深层链接和应用链接来引导流量到目标应用。

实现您自己的助理

您可能希望实现您自己的助理。如图 2 所示,用户可以选择激活的助理应用。助理应用必须提供 VoiceInteractionSessionServiceVoiceInteractionSession 的实现,如VoiceInteraction 示例所示。它还需要 BIND_VOICE_INTERACTION 权限。助理随后可以在 onHandleAssist() 中接收表示为 AssistStructure 实例的文本和视图层次结构。它通过 onHandleScreenshot() 接收屏幕截图。