透過應用程式動作,將動態捷徑功能延伸至 Google 助理

透過應用程式動作,將動態捷徑功能延伸至 Google 助理

程式碼研究室簡介

subject上次更新時間:9月 12, 2024
account_circle作者:Google Assistant Developer Relations

1. 總覽

先前的程式碼研究室中,您使用靜態捷徑在範例應用程式中實作常用的內建意圖 (BII)。Android 開發人員會使用應用程式動作,將應用程式功能擴充至 Google 助理。

靜態捷徑會與應用程式捆綁,只能透過發布應用程式的新版本來更新。如要為應用程式中的動態元素 (例如使用者產生的內容) 啟用語音功能,請使用動態捷徑。應用程式會在使用者執行相關動作後推送動態捷徑,例如在工作追蹤應用程式中建立新記事。透過應用程式動作,您可以將這些語音快速指令繫結至 BII,讓使用者透過 Google 助理存取自己的內容,例如「Ok Google,在範例應用程式中開啟我的雜貨清單」

三個逐步畫面,顯示 Google 助理啟動動態捷徑。

圖 1. 三個漸進式畫面,顯示使用者建立的工作,以及 Google 助理啟動該工作項目的動態捷徑。

在本程式碼研究室中,您將使用範例待辦事項清單 Android 應用程式啟用語音的動態捷徑,讓使用者可以要求 Google 助理開啟他們在應用程式中建立的工作清單項目。您可以使用 Android 架構模式完成這項操作,特別是存放區服務定位器ViewModel 模式。

必要條件

本程式碼研究室會延續先前的程式碼研究室中介紹的應用程式動作概念,特別是 BII 和靜態捷徑。如果您是 App Actions 新手,建議您先完成該程式碼研究室,再繼續操作。

此外,請先確認開發環境具有以下設定,再繼續操作:

  • 終端機,可在安裝 Git 的情況下執行 Shell 指令。
  • 最新的 Android Studio 穩定版。
  • 可連上網際網路的實體或虛擬 Android 裝置。
  • 已登入 Android Studio、Google 應用程式和 Google 助理應用程式的 Google 帳戶。

2. 瞭解運作方式

請按照下列步驟啟用語音存取的動態捷徑:

  • 將動態捷徑繫結至符合資格的 BII。
  • 新增 Google 捷徑整合資料庫,讓 Google 助理擷取捷徑。
  • 在使用者完成相關的應用程式內工作時推送捷徑。

繫結快速鍵

如要透過 Google 助理使用動態捷徑,該捷徑必須繫結至相關 BII。觸發含有捷徑的 BII 時,Google 助理會比對使用者要求中的參數與繫結捷徑中定義的關鍵字。例如:

  • 繫結至 GET_THING BII 的捷徑可讓使用者直接從 Google 助理要求特定應用程式內容。* 「Ok Google,在範例應用程式中開啟我的購物清單。」
  • 使用者可以透過與 START_EXERCISE BII 繫結的捷徑,查看自己的運動時段。*「Ok Google,要求範例應用程式開啟平常的運動。」

如需完整的 BII 分類清單,請參閱內建意圖參考資料

提供 Google 助理捷徑

將捷徑繫結至 BII 後,下一步就是在專案中新增 Google 捷徑整合程式庫,讓 Google 助理擷取這些捷徑。這個程式庫可讓 Google 助理瞭解應用程式推送的每個捷徑,讓使用者在 Google 助理中使用捷徑的觸發字詞啟動這些捷徑。

3. 準備開發環境

本程式碼研究室會使用專為 Android 建構的範例待辦事項清單應用程式。使用者可以透過這個應用程式將項目新增至清單、依類別搜尋工作清單項目,以及依完成狀態篩選工作。完成本節即可下載範例應用程式,並準備完成。

下載基礎檔案

執行下列指令,複製範例應用程式的 GitHub 存放區:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git

複製存放區後,請按照下列步驟在 Android Studio 中開啟存放區:

  1. 在「Welcome to Android Studio」對話方塊中,按一下「Import project」
  2. 選取複製存放區的資料夾。

或者,您也可以複製 GitHub 存放區的 codelab-complete 分支版本,藉此查看代表已完成程式碼研究室的範例應用程式版本:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete

更新 Android 應用程式 ID

更新應用程式 ID 可在測試裝置上識別出唯一的應用程式,並避免在將應用程式上傳至 Play 管理中心時發生「重複的套件名稱」錯誤。如要更新應用程式 ID,請開啟 app/build.gradle

android {
...
  defaultConfig
{
    applicationId
"com.MYUNIQUENAME.android.fitactions"
   
...
 
}
}

取代「MYUNIQUENAME」在 applicationId 欄位中使用不重複的值。

新增 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'
   ...
}

在裝置上測試應用程式

在對應用程式進行更多變更之前,建議您先瞭解範例應用程式的功能。如要在模擬器上執行應用程式,請按照下列步驟操作:

  1. 在 Android Studio 中,依序選取「Run」(執行) >執行應用程式,或按一下工具列中的「Run」Android Studio 中的「Run app」圖示
  2. 在「Select Deployment Target」對話方塊中,選取裝置,然後按一下「OK」。推薦使用的 OS 版本為 Android 10 (API 級別 30) 以上,不過應用程式動作可支援至 Android 5 (API 級別 21) 的裝置。
  3. 長按主畫面按鈕設定 Google 助理,並確認 Google 助理是否正常運作。如果你尚未在裝置上登入 Google 助理,請先登入。

如要進一步瞭解 Android 虛擬裝置,請參閱「建立及管理虛擬裝置」。

簡短探索這個應用程式的功能。輕觸「加號」圖示會建立一個新的工作項目,而右上方的選單項目則可讓您依完成狀態搜尋及篩選工作項目。

4. 建立捷徑存放區類別

範例應用程式中的幾個類別會呼叫 ShortcutManagerCompat API,以便推送及管理動態捷徑。為了減少程式碼的備援能力,您將實作存放區,讓專案類別輕鬆管理動態捷徑。

存放區設計模式提供簡潔的 API,可用來管理捷徑。存放區的優點在於基礎 API 的細節會在最小 API 背後完整擷取。請按照下列步驟實作存放區:

  1. 建立 ShortcutsRepository 類別,以便抽象化 ShortcutManagerCompat API。
  2. ShortcutsRepository 方法新增至應用程式的服務定位器
  3. 在主要應用程式中註冊 ShortcutRepository 服務。

建立存放區

com.example.android.architecture.blueprints.todoapp.data.source 套件中建立名為 ShortcutsRepository 的新 Kotlin 類別。你可以在 app/src/main/java 資料夾中找到這個套件。您將使用此類別實作一個介面,提供涵蓋程式碼研究室用途最精簡的方法組合。

Android Studio 視窗,顯示 ShortcutsRepository 類別的位置。

圖 2. Android Studio「Project Files」視窗顯示 ShortcutsRepository 類別的位置。

將下列程式碼貼入新類別中:

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。此為保存應用程式結構定義的類別屬性。為了避免記憶體耗損,請務必使用應用程式內容 (而非活動內容),因為內容可能會保留的時間比主機活動生命週期還長。

此外,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 類別後,下一步是讓應用程式的其餘部分可使用此類別的例項化物件。這個應用程式會透過實作 服務定位器模式來管理類別依附元件。依序點選「Navigate」> > 即可使用 Android Studio 中的類別瀏覽器開啟服務定位器類別。Class 並輸入「ServiceLocator」。按一下產生的 Kotlin 檔案,即可在 IDE 中開啟該檔案。

ServiceLocator.kt 頂端貼上以下程式碼,以匯入 ShortcutsRepositorySuppressLint 套件:

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)
       }
   }
 }

註冊捷徑服務

最後一步是向應用程式註冊新的「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 的動態捷徑,以便透過語音存取這項內容。這樣一來,當使用者透過「Ok Google,在 SampleApp 中開啟我的購物清單」等指令觸發 BII 時,Google 助理就能直接啟動使用者要求的任務項目。

如要在範例應用程式中啟用這項功能,請完成下列步驟:

  1. ShortcutsRepository 服務匯入 AddEditTaskViewModel 類別,負責管理工作清單物件。
  2. 在使用者建立新工作時推送動態捷徑。

匯入 ShortcutsRepository

我們首先需要讓 ShortcutsRepository 服務可供 AddEditTaskViewModel 使用。如要完成這項操作,請將服務匯入 ViewModelFactory,這是應用程式用來例項化 ViewModel 物件 (包括 AddEditTaskViewModel) 的工廠類別。

依序前往「Navigate」> > 在 Android Studio 中開啟類別瀏覽器。Class 並輸入「ViewModelFactory」。按一下產生的 Kotlin 檔案,即可在 IDE 中開啟該檔案。

ViewModelFactory.kt 頂端貼上以下程式碼,以匯入 ShortcutsRepositorySuppressLint 套件:

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 中開啟該檔案。

首先,請使用下列匯入陳述式,將 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 中安裝:

  1. 依序前往「File」>「Settings」(macOS 中為「Android Studio」>「Preferences」)。
  2. 在「外掛程式」部分中,前往「Marketplace」並搜尋「Google 助理」。
  3. 安裝工具,然後重新啟動 Android Studio。

建立預覽畫面

在 Android Studio 中,按照下列步驟建立預覽:

  1. 依序點選「Tools」>「Google Assistant」>「App Actions Test Tool」
  2. 在「應用程式名稱」方塊中,定義名稱,例如「待辦事項清單」。
  3. 按一下「Create Preview」。如果系統要求,請詳閱並接受應用程式動作政策和服務條款。

應用程式動作測試工具的預覽建立窗格。

圖 3. 應用程式動作測試工具預覽建立窗格。

在測試期間,你推送至 Google 助理的動態捷徑會顯示在 Google 助理中,並依據你為預先發布版提供的應用程式名稱分門別類。

推送及檢查捷徑

在測試裝置上重新啟動範例應用程式,然後執行下列步驟:

  1. 建立標題為「Start Codelab」的新工作
  2. 開啟 Google 助理應用程式,然後說出或輸入「我的捷徑」。
  3. 輕觸「探索」分頁標籤。你應該會看到範例捷徑。
  4. 輕觸捷徑即可叫用。您應該會看到應用程式啟動,且快速鍵名稱已預先填入篩選器方塊,讓您更容易找到要求的工作項目。

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)
   }
}

請重新啟動應用程式,然後按照以下步驟測試程式碼:

  1. 將現有工作項目的標題重新命名為「Finish codelab」。
  2. 說出「Ok Google,我的捷徑」來開啟 Google 助理。
  3. 輕觸「探索」分頁標籤。您應該會看到測試用捷徑的最新簡短標籤。

移除捷徑

使用者刪除工作時,都應該移除範例應用程式的捷徑。在範例應用程式中,工作刪除邏輯位於 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))
   
}
}

如要測試程式碼,請重新啟動應用程式,然後按照下列步驟操作:

  1. 刪除測試工作。
  2. 將現有工作項目的標題重新命名為「Finish codelab」。
  3. 說出「Ok Google,我的捷徑」來開啟 Google 助理。
  4. 輕觸「探索」分頁標籤。確認測試捷徑已經消失。

7. 後續步驟

恭喜!多虧了您,現在範例應用程式的使用者只要對 Google 助理說出「Ok Google,在範例應用程式中開啟我的購物清單」,就能輕鬆返回所建立的記事。捷徑可讓使用者輕鬆重播常用的應用程式動作,藉此吸引使用者進一步互動。

涵蓋內容

在本程式碼研究室中,您學到如何:

  • 找出在應用程式中推送動態捷徑的用途。
  • 使用存放區、依附元件插入和服務定位器設計模式,降低程式碼複雜度。
  • 將支援語音的動態捷徑推送至使用者自製的應用程式內容。
  • 更新及移除現有的捷徑。

後續步驟

從這裡開始,您可以嘗試進一步改善 Task List 應用程式。如要參考完成的專案,請前往 GitHub 上的存放區 –codelab-complete 分支

以下提供一些建議,協助您進一步瞭解如何使用應用程式動作擴充這個應用程式:

如要繼續使用 Google 動作,請參閱下列資源:

歡迎追蹤我們的 Twitter 帳號 @ActionsOnGoogle,隨時掌握最新公告,並在推文中使用 #appActions 標籤,分享您建立的內容!

意見調查

最後,請填寫這份問卷調查,針對您使用本程式碼研究室的體驗提供意見。