1. 概览
在上一个 Codelab 中,你使用静态快捷方式在示例应用中实现了常用的内置 intent (BII)。Android 开发者使用与应用有关的 Action 将应用功能扩展到 Google 助理。
静态快捷方式与应用捆绑,并且只能通过发布应用的新版本进行更新。为应用中的动态元素(例如用户生成的内容)启用语音功能可以通过动态快捷方式来实现。用户执行相关操作(例如在任务跟踪应用中创建新记事)后,应用会推送动态快捷方式。借助与应用有关的 Action,你可以将这些快捷方式与 BII 绑定,以启用语音功能,这样用户就可以通过说出“Hey Google, open my grocery list on ExampleApp”这样的语音指令从 Google 助理访问内容。
图 1. 三个进程屏幕,显示的是用户创建任务以及 Google 助理启动该任务项的动态快捷方式。
构建内容
在此 Codelab 中,你将在一个示例待办事项列表 Android 应用中启用动态语音快捷方式,让用户能够要求 Google 助理打开他们在应用中创建的任务列表项。为此,你可以使用 Android 架构模式,特别是代码库、服务定位器和 ViewModel 模式。
前提条件
本 Codelab 是建立在上一个 Codelab 中涵盖的与应用有关的 Action 概念的基础上,尤其是 BII 和静态快捷方式。如果你不熟悉与应用有关的 Action,我们建议你先完成本 Codelab 的学习,然后再继续。
此外,请确保你的开发环境具有以下配置,然后再继续:
- 已安装 git 的终端,用于运行 shell 命令。
- Android Studio 的最新稳定版本。
- 一部可以访问互联网的 Android 实体设备或虚拟设备。
- 已登录 Android Studio、Google 应用和 Google 助理应用的 Google 帐号。
2. 了解运作方式
启用 Voice Access 的动态快捷方式涉及以下步骤:
- 将动态快捷方式绑定到符合条件的 BII。
- 通过添加 Google 快捷方式集成库,使 Google 助理能够提取快捷方式。
- 在用户完成相关的应用内任务时推送快捷方式。
绑定快捷方式
要通过 Google 助理访问动态快捷方式,需要将其绑定到相关的 BII。当触发具有快捷方式的 BII 时,Google 助理会将用户请求中的参数与绑定的快捷方式中定义的关键字匹配。例如:
- 绑定到
GET_THING
BII 的快捷方式可让用户直接通过 Google 助理请求特定应用内内容。*“Hey Google, open my grocery list on ExampleApp.” - 绑定到
ORDER_MENU_ITEM
BII 的快捷方式可让用户再次执行之前的订单。*“Hey Google, order my usual from ExampleApp.”
如需查看完整的 BII 分类列表,请参阅内置 intent 参考文档。
为 Google 助理提供快捷方式
将快捷方式绑定到 BII 后,下一步是将 Google 快捷方式集成库添加到你的项目中,让 Google 助理能够提取这些快捷方式。添加此库后,Google 助理会识别你应用推送的每个快捷方式,让用户能够通过在 Google 助理中使用快捷方式的触发短语来启动这些快捷方式。
3. 准备开发环境
本 Codelab 使用专为 Android 构建的示例待办事项列表应用。借助此应用,用户可以将内容添加到列表中、按类别搜索任务列表项以及按完成状态过滤任务。完成此部分,下载并准备示例应用。
下载基础文件
运行以下命令以克隆示例应用的 GitHub 代码库:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git
克隆完代码库后,按照以下步骤在 Android Studio 中将其打开:
- 在 Welcome to Android Studio 对话框中,点击 Import project。
- 选择克隆代码库的文件夹。
或者,你也可以通过克隆其 GitHub 代码库的 codelab-complete
分支来查看代表已完成的 Codelab 的示例应用版本:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete
添加 Shortcuts API 依赖项
将以下 Jetpack 库添加到 app/build.gradle
资源文件:
app/build.gradle
dependencies {
...
// Shortcuts library
implementation "androidx.core:core:1.6.0"
implementation 'androidx.core:core-google-shortcuts:1.0.1'
...
}
添加唯一的应用 ID
在本 Codelab 后面的内容中,你将使用 Google 助理插件,让快捷方式在实体设备或虚拟设备上对 Google 助理可见。该测试工具要求将你的应用上传到 Google Play 管理中心内的某个项目。为避免在上传应用时出现“Duplicate package name”错误,请将示例应用的 applicationId
更改为唯一 ID。
在 app/build.gradle
中,将 applicationId
值“com.example.myapp”更新为唯一 ID,例如“com.codelabs.myname”。如需详细了解 applicationIds
,请参阅设置应用 ID。以下代码段展示了更新后的 applicationId
:
android {
...
defaultConfig {
// This ID uniquely identifies your app on the device and in Google Play Store
applicationId "com.example.myapp"
...
}
}
在 src/res/xml/shortcuts.xml 中,将 android:targetPackage
的所有实例的值更新为唯一的 applicationId
。例如:
<capability android:name="actions.intent.GET_THING">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.codelabs.myname"
...>
</intent>
</capability>
在设备上测试应用
在对该应用进行更多更改之前,最好了解一下该示例应用的功能。如需在模拟器上运行该应用,请按以下步骤操作:
- 在 Android Studio 中,依次选择“Run”>“Run app”,或点击工具栏中的 Run 图标 。
- 在 Select Deployment Target 对话框中,选择虚拟设备,然后点击 OK。虽然与应用有关的 Action 在搭载 Android 5(API 级别 21)的设备上也能运行,但我们推荐使用的操作系统版本为 Android 10(API 级别 30)或更高版本。
- 长按主屏幕按钮,以设置 Google 助理并验证它能否正常运行。你需要在设备上登录 Google 助理(如果你尚未登录的话)。
如需详细了解 Android 虚拟设备,请参阅创建和管理虚拟设备。
快速浏览该应用以了解其功能。点按加号图标可创建新的任务项;借助右上角的菜单项,你可以按完成状态搜索和过滤任务项。
上传到 Play 管理中心
你必须将应用上传到 Google Play 管理中心内的项目,然后才能在 Android Studio 中使用 Google 助理插件。在 Android Studio 中构建您的应用,并将其作为内部版本草稿上传到 Play 管理中心。
如需在 Android Studio 中构建应用,请按以下步骤操作:
- 依次点击“Build > Generate Signed Bundle / APK”。
- 选择“Android App Bundle”,然后点击“Next”。
- 输入详细信息以对应用进行签名,然后点击“Next”。
- 选择 prodRelease build 变体,然后点击“Finish”。
在 Play 管理中心内,请按照以下步骤将你刚刚创建的 app bundle 作为新应用进行上传:
- 在“所有应用”页面上,点击创建应用。
- 随意为该应用命名,然后点击创建应用。在本 Codelab 中,您无需在应用创建完成后填写任何应用信息。
- 在边栏菜单中,转到测试并找到 内部测试页面。
- 点击内部测试页面上的创建新版本。
- 点击继续以同意使用 Google Play 应用签名。
- 在 app bundle 和 APK 面板中,上传您之前生成的 AAB 文件(该文件可能位于
app/prod/release
目录中)。点击保存。
4. 创建快捷方式代码库类
示例应用中的多个类将调用 ShortcutManagerCompat
API 以推送和管理动态快捷方式。为了减少代码冗余,你将实现一个代码库,让项目类能够轻松管理动态快捷方式。
代码库设计模式提供了一个整洁有序的 API 来管理快捷方式。代码库的优点是底层 API 的细节在最小的 API 后统一抽象。请按照以下步骤来实现代码库:
- 创建
ShortcutsRepository
类以抽象化ShortcutManagerCompat
API。 - 将
ShortcutsRepository
方法添加到应用的服务定位器。 - 在主应用中注册
ShortcutRepository
服务。
创建代码库
在 com.example.android.architecture.blueprints.todoapp.data.source
软件包中创建一个名为 ShortcutsRepository
的新 Kotlin 类。你可以在 app/src/main/java
文件夹中找到此软件包。你将使用该类来实现一个接口,该接口提供了一套涵盖我们 Codelab 用例的基本方法。
图 2. Android Studio 中,显示 ShortcutsRepository 类位置的“Project Files”窗口。
将以下代码粘贴到新类中:
package com.example.android.architecture.blueprints.todoapp.data.source
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import com.example.android.architecture.blueprints.todoapp.data.Task
import com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity
private const val GET_THING_KEY = "q"
/**
* ShortcutsRepository provides an interface for managing dynamic shortcuts.
*/
class ShortcutsRepository(val context: Context) {
private val appContext = context.applicationContext
/**
* Pushes a dynamic shortcut. The task ID is used as the shortcut ID.
* The task's title and description are used as shortcut's short and long labels.
* The resulting shortcut corresponds to the GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
// TODO
}
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
//...
}
/**
* Updates a dynamic shortcut for the provided task. If the shortcut
* associated with this task doesn't exist, this method throws an error.
* This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
//...
}
/**
* Removes shortcuts if IDs are known.
*
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
//...
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
//...
}
}
接下来,更新 pushShortcut
方法以调用 ShortcutManagerCompat
API。请使用以下代码更新 ShortcutsRepository
类:
ShortcutsRepository.kt
/**
* Pushes a dynamic shortcut for the task. The task's ID is used as a shortcut
* ID. The task's title and description are used as shortcut's short and long
* labels. The created shortcut corresponds to GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
ShortcutManagerCompat.pushDynamicShortcut(appContext, createShortcutCompat(task))
}
在前面的代码示例中,我们已将 appContext
传递给了 API。这是一个包含应用上下文的类属性。若要避免内存泄漏,就一定要使用应用上下文(而不是 activity 上下文),因为上下文的保留期限可能会比宿主 activity 生命周期长。
此外,API 还要求为 Task 对象传递 ShortcutInfoCompat
对象。在前面的代码示例中,我们通过调用 createShortcutCompat
私有方法完成此操作。我们将更新该方法,以创建并返回 ShortcutInfoCompat
对象。为此,请使用以下代码更新 createShortcutCompat
桩:
ShortcutsRepository.kt
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
val intent = Intent(appContext, TasksActivity::class.java)
intent.action = Intent.ACTION_VIEW
// Filtering is set based on currentTitle.
intent.putExtra(GET_THING_KEY, task.title)
// A unique ID is required to avoid overwriting an existing shortcut.
return ShortcutInfoCompat.Builder(appContext, task.id)
.setShortLabel(task.title)
.setLongLabel(task.title)
// Call addCapabilityBinding() to link this shortcut to a BII. Enables user to invoke a shortcut using its title in Assistant.
.addCapabilityBinding(
"actions.intent.GET_THING", "thing.name", listOf(task.title))
.setIntent(intent)
.setLongLived(false)
.build()
}
此类中的其余函数桩负责更新和删除动态快捷方式。使用以下代码更新这些函数即可启用它们:
ShortcutsRepository.kt
/**
* Updates a Dynamic Shortcut for the task. If the shortcut associated with this task
* doesn't exist, throws an error. This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
val scs = tasks.map { createShortcutCompat(it) }
ShortcutManagerCompat.updateShortcuts(appContext, scs)
}
/**
* Removes shortcuts if IDs are known.
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
ShortcutManagerCompat.removeDynamicShortcuts(appContext, ids)
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
ShortcutManagerCompat.removeDynamicShortcuts (appContext,
tasks.map { it.id })
}
将类添加到服务定位器
创建 ShortcutsRepository
类后,下一步是将该类的实例化对象提供给应用的其余部分。此应用通过实现服务定位器模式来管理类依赖项。在 Android Studio 中使用类浏览器打开服务定位器类,方法是依次点击 Navigate > Class,然后输入“ServiceLocator”。点击生成的 Kotlin 文件,在 IDE 中将其打开。
在 ServiceLocator.kt
顶部,粘贴以下代码以导入 ShortcutsRepository
和 SuppressLint
软件包:
ServiceLocator.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
import android.annotation.SuppressLint
将以下代码粘贴到 ServiceLocator.kt
的正文中,以添加 ShortcutRepository
服务成员和方法:
ServiceLocator.kt
object ServiceLocator {
// ...
// Only the code immediately below this comment needs to be copied and pasted
// into the body of ServiceLocator.kt:
@SuppressLint("StaticFieldLeak")
@Volatile
var shortcutsRepository: ShortcutsRepository? = null
private fun createShortcutsRepository(context: Context): ShortcutsRepository {
val newRepo = ShortcutsRepository(context.applicationContext)
shortcutsRepository = newRepo
return newRepo
}
fun provideShortcutsRepository(context: Context): ShortcutsRepository {
synchronized(this) {
return shortcutsRepository ?: shortcutsRepository ?: createShortcutsRepository(context)
}
}
}
注册快捷方式服务
最后一步是向 Application 注册新的 ShortcutsRepository
服务。在 Android Studio 中,打开 TodoApplication.kt
并复制文件顶部附近的以下代码:
TodoApplication.kt
package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
接下来,将以下代码添加到类的正文中,以注册该服务:
TodoApplication.kt
//...
class TodoApplication : Application() {
//...
val shortcutsRepository: ShortcutsRepository
get() = ServiceLocator.provideShortcutsRepository(this)
//...
}
构建应用并确保其继续运行。
5. 推送新的快捷方式
创建快捷方式服务后,你就可以开始推送快捷方式了。由于用户在此应用中生成内容(任务项),并期望稍后能够返回这些内容,因此,每次用户创建新任务时,我们将通过推送一个绑定到 GET_THING
BII 的动态快捷方式来启用对此内容的语音访问。这样,当用户通过说出“Hey Google, open my grocery list on SampleApp”这样的语音指令来触发 BII 后,Google 助理便可以直接启动用户请求的任务项。
你可以按照以下步骤在示例应用中启用此功能:
- 将
ShortcutsRepository
服务导入到AddEditTaskViewModel
类,后者负责管理任务列表对象。 - 在用户创建新任务时推送动态快捷方式。
导入 ShortcutsRepository
我们首先需要将 ShortcutsRepository
服务提供给 AddEditTaskViewModel
。为此,请将该服务导入到 ViewModelFactory
,这是应用用于实例化 ViewModel 对象的工厂类,包括 AddEditTaskViewModel
。
在 Android Studio 中打开类浏览器,方法是依次点击 Navigate > Class,然后输入“ViewModelFactory”。点击生成的 Kotlin 文件,在 IDE 中将其打开。
在 ViewModelFactory.kt
顶部,粘贴以下代码以导入 ShortcutsRepository
和 SuppressLint
软件包:
ViewModelFactory.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
接下来,将 ViewModelFactory
的正文替换为以下代码:
ViewModelFactory.kt
/**
* Factory for all ViewModels.
*/
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
向上移动一层,完成 ViewModelFactory
更改,并将 ShortcutsRepository
传递给工厂的构造函数。依次点击 Navigate > File,然后输入“FragmentExt.kt”,打开 Android Studio 的文件浏览器。点击在 util 软件包中生成的 Kotlin 文件,以在 IDE 中打开它。
将 FragmentExt.kt
的正文替换为以下代码:
fun Fragment.getViewModelFactory(): ViewModelFactory {
val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
return ViewModelFactory(taskRepository, shortcutsRepository, this)
}
推送快捷方式
通过为示例应用的 ViewModel
类提供 ShortcutsRepository
抽象类,你可以更新 AddEditTaskViewModel
(即负责创建记事的 ViewModel
类),在用户每次创建新记事时推送动态快捷方式。
在 Android Studio 中,打开类浏览器并输入“AddEditTaskViewModel”。点击生成的 Kotlin 文件,在 IDE 中将其打开。
首先,使用以下 import 语句将 ShortcutsRepository
软件包添加到此类:
package com.example.android.architecture.blueprints.todoapp.addedittask
//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
接下来,使用以下代码更新类构造函数,以添加 shortcutsRepository
类属性:
AddEditTaskViewModel.kt
//...
/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
//...
添加 ShortcutsRepository
类后,创建一个新函数 pushShortcut()
来调用此类。将以下私有函数粘贴到 AddEditTaskViewModel
的正文中:
AddEditTaskViewModel.kt
//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.pushShortcut(newTask)
}
最后,在每次创建任务时推送一个新的动态快捷方式。将 saveTask()
函数的内容替换为以下代码:
AddEditTaskViewModel.kt
fun saveTask() {
val currentTitle = title.value
val currentDescription = description.value
if (currentTitle == null || currentDescription == null) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
if (Task(currentTitle, currentDescription).isEmpty) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
val currentTaskId = taskId
if (isNewTask || currentTaskId == null) {
val task = Task(currentTitle, currentDescription)
createTask(task)
pushShortcut(task)
} else {
val task = Task(currentTitle, currentDescription, taskCompleted, currentTaskId)
updateTask(task)
}
}
测试代码
我们终于准备好测试代码啦!在此步骤中,你将推送支持语音功能的动态快捷方式,并使用 Google 助理应用对其进行检查。
创建预览
使用 Google 助理插件创建预览后,你的动态快捷方式会出现在测试设备上的 Google 助理中。
安装测试插件
如果你还没有安装 Google 助理插件,请按以下步骤在 Android Studio 中安装该插件:
- 依次点击**“File > Settings”(在 MacOS 中,依次点击“Android Studio > Preferences”)。
- 在 Plugins 部分中,点击 Marketplace,然后搜索“Google Assistant”。
- 安装该工具,然后重启 Android Studio。
创建预览
在 Android Studio 中按照以下步骤创建预览:
- 依次点击 Tools > Google Assistant > App Actions Test Tool。
- 在 App name 框中,指定一个名称,如“Todo List”。
- 点击 Create Preview。
图 3. 与应用有关的 Action 测试工具预览创建窗格。
在测试期间,你推送到 Google 助理的动态快捷方式会出现在 Google 助理中,按你为预览提供的应用名称整理。
推送和检查快捷方式
在测试设备上重新启动示例应用,然后执行以下步骤:
- 创建一个标题为“Start codelab”的新任务
- 打开 Google 助理应用,然后说出或输入“My shortcuts”。
- 点按探索标签页。你应该会看到示例快捷方式。
- 点按快捷方式以调用它。你应该会看到,应用启动时,过滤框中预先填充了快捷方式的名称,以便你轻松找到请求的任务项。
6. (可选)更新和删除快捷方式
除了在运行时推送新的动态快捷方式之外,你的应用还可以更新这些快捷方式,以反映用户内容和偏好设置的当前状态。最好在用户修改目标项时(例如重命名示例应用中的任务)更新现有快捷方式。此外,每当移除目标资源时,也应删除相应的快捷方式,以避免向用户显示损坏的快捷方式。
更新快捷方式
修改 AddEditTaskViewModel
,以便在用户更改任务项的详细信息时更新动态快捷方式。首先,使用以下代码更新类的正文,以添加利用我们的代码库类的更新函数:
AddEditTaskViewModel.kt
private fun updateShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.updateShortcuts(listOf(newTask))
}
接下来,修改 saveTask()
函数,以便在现有任务更新时调用我们的新方法。
AddEditTaskViewModel.kt
// Called when clicking on fab.
fun saveTask() {
// ...
// Note: the shortcuts are created/updated in a worker thread.
if (isNewTask || currentTaskId == null) {
//...
} else {
//...
updateShortcut(task)
}
}
通过重新启动应用并执行以下步骤来测试你的代码:
- 将现有任务项的标题重命名为“Finish codelab”。
- 说出“Hey Google, my shortcuts”,打开 Google 助理。
- 点按探索标签页。你应该会看到测试快捷方式的更新短标签。
移除快捷方式
每当用户删除任务时,我们都应该移除我们的示例应用快捷方式。在示例应用中,任务删除逻辑位于 TaskDetailViewModel
类中。在更新此类之前,我们需要再次更新 ViewModelFactory
,以将 shortcutsRepository
传递到 TaskDetailViewModel
。
打开 ViewModelFactory
并将其构造函数方法的内容替换为以下代码:
//...
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
接着,打开 TaskDetailViewModel
。使用以下代码导入 ShortcutsRepository
模块并为其声明实例变量:
TaskDetailViewModel.kt
package com.example.android.architecture.blueprints.todoapp.taskdetail
...
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
/**
* ViewModel for the Details screen.
*/
class TaskDetailViewModel(
//...
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
...
}
最后,修改 deleteTask()
函数来调用 shortcutsRepository
,以便在删除具有相应 taskId
的任务时根据 ID 来移除快捷方式。
TaskDetailViewModel.kt
fun deleteTask() = viewModelScope.launch {
_taskId.value?.let {
//...
shortcutsRepository.removeShortcutsById(listOf(it))
}
}
如需测试你的代码,请重新启动该应用并执行以下步骤:
- 删除测试任务。
- 将现有任务项的标题重命名为“Finish codelab”。
- 说出“Hey Google, my shortcuts”,打开 Google 助理。
- 点按探索标签页。确认你的测试快捷方式不再出现。
7. 后续步骤
恭喜! 多亏有你,我们示例应用的用户才能通过向 Google 助理发出“Hey Google, open my grocery list on ExampleApp”这样的语音指令,轻松返回到他们创建的记事。快捷方式让用户可以轻松地在应用中再次执行常用操作,从而鼓励用户更深入地互动。
所学内容
在本 Codelab 中,你学习了如何:
- 确定在应用中推送动态快捷方式的用例。
- 使用代码库、依赖项注入和服务定位器设计模式降低代码复杂性。
- 将支持语音功能的动态快捷方式推送到用户生成的应用内容。
- 更新和移除现有快捷方式。
后续操作
接下来,你可以尝试进一步优化你的任务列表应用。如需参考完成后的项目,请参阅 GitHub 上的代码库的 –codelab-complete 分支。
如需进一步了解如何使用与应用有关的 Action 扩展该应用,请参阅以下建议:
- 查看采用 Google Analytics for Firebase 的待办事项列表示例,了解如何跟踪与应用有关的 Action 的表现。
- 访问与应用有关的 Action“内置 intent”参考文档,探索将你的应用扩展到 Google 助理的更多方法。
如需继续了解 Actions on Google,请浏览下列资源:
- actions.google.com:Actions on Google 的官方文档网站。
- 与应用有关的 Action 示例索引:用于探索与应用有关的 Action 的功能的示例应用和代码。
- Actions on Google GitHub 代码库:示例代码和库。
- r/GoogleAssistantDev:从事 Google 助理相关工作的开发者的官方 Reddit 社区。
欢迎关注我们的 Twitter 帐号 @ActionsOnGoogle,及时了解我们的最新公告,还可以使用标签 #appActions 发布 Twitter 微博,分享你构建的成果!
反馈意见调查
最后,请填写该调查问卷,就您学习本 Codelab 的体验提供反馈意见。