Rozszerzaj dynamiczne skróty do Asystenta Google za pomocą działań w aplikacji

1. Przegląd

poprzednim Codelabs za pomocą skrótów statycznych zaimplementowano w przykładowej aplikacji często używane wbudowane intencje (BII). Programiści na Androida używają działań w aplikacji, aby rozszerzyć funkcje aplikacji na Asystenta Google.

Statyczne skróty są dołączane do aplikacji i można je aktualizować tylko przez wydawanie nowych wersji aplikacji. Włączanie funkcji głosowych dla dynamicznych elementów w aplikacji, takich jak treści użytkowników, odbywa się za pomocą dynamicznych skrótów. Aplikacje wysyłają skróty dynamiczne po wykonaniu przez użytkowników odpowiednich działań, np. utworzeniu nowej notatki w aplikacji do śledzenia zadań. Dzięki działaniom w aplikacji możesz włączyć te skróty dla poleceń głosowych, wiążąc je z BII. Umożliwi to użytkownikom dostęp do treści z poziomu Asystenta za pomocą poleceń takich jak „OK Google, otwórz moją listę zakupów w ExampleApp”.

Trzy ekrany pokazujące, jak Asystent Google uruchamia skrót dynamiczny.

Rysunek 1. Trzy ekrany progresywne przedstawiające zadanie utworzone przez użytkownika i Asystenta Google uruchamiającego dynamiczny skrót do tego zadania.

Co utworzysz

W tym module nauczysz się włączać dynamiczne skróty głosowe w przykładowej aplikacji na Androida z listą zadań do wykonania. Dzięki temu użytkownicy będą mogli poprosić Asystenta o otwarcie elementów listy zadań utworzonych w aplikacji. Aby to zrobić, użyjesz wzorców architektury Androida, a w szczególności wzorców repository, service locatorViewModel.

Wymagania wstępne

Ten samouczek opiera się na koncepcjach działań w aplikacji omówionych w poprzednim samouczku, zwłaszcza na wbudowanych intencjach i statycznych skrótach. Jeśli nie masz doświadczenia w korzystaniu z akcji w aplikacji, przed przejściem dalej zalecamy ukończenie tego laboratorium programowania.

Zanim przejdziesz dalej, upewnij się, że Twoje środowisko programistyczne ma taką konfigurację:

  • terminal do uruchamiania poleceń powłoki z zainstalowanym narzędziem Git;
  • Najnowsza stabilna wersja Android Studio.
  • fizyczne lub wirtualne urządzenie z Androidem z dostępem do internetu;
  • konto Google zalogowane w Android Studio, aplikacji Google i aplikacji Asystent Google;

2. Jak to działa

Aby włączyć dynamiczny skrót do dostępu głosowego, wykonaj te czynności:

  • Powiązanie skrótu dynamicznego z odpowiednim wbudowanym zamiarem.
  • Umożliwienie Asystentowi korzystania ze skrótów przez dodanie biblioteki integracji skrótów Google.
  • Wysyłanie skrótu za każdym razem, gdy użytkownik wykona odpowiednie zadanie w aplikacji.

Przypisywanie skrótów

Aby skrót dynamiczny był dostępny z poziomu Asystenta, musi być powiązany z odpowiednim BII. Gdy wywoływany jest wbudowany zamiar z skrótem, Asystent dopasowuje parametry w żądaniu użytkownika do słów kluczowych zdefiniowanych w powiązanym skrócie. Na przykład:

  • Skrót powiązany z GET_THING BII może umożliwiać użytkownikom żądanie określonych treści w aplikacji bezpośrednio z Asystenta. * „OK Google, otwórz moją listę zakupów w aplikacji ExampleApp”.
  • Skrót powiązany z START_EXERCISE BII może umożliwiać użytkownikom wyświetlanie sesji ćwiczeń. * „OK Google, poproś ExampleApp o rozpoczęcie mojego zwykłego treningu”.

Pełną listę wbudowanych intencji znajdziesz w dokumentacji wbudowanych intencji.

Udostępnianie skrótów Asystentowi

Po powiązaniu skrótów z BII następnym krokiem jest umożliwienie Asystentowi korzystania z tych skrótów przez dodanie do projektu biblioteki integracji skrótów Google. Dzięki tej bibliotece Asystent będzie znać każdy skrót przesłany przez Twoją aplikację, co umożliwi użytkownikom uruchamianie tych skrótów za pomocą frazy wywołującej w Asystencie.

3. Przygotowywanie środowiska programistycznego

W tym ćwiczeniu w Codelabs używamy przykładowej aplikacji do tworzenia list zadań do wykonania na Androida. Dzięki tej aplikacji użytkownicy mogą dodawać elementy do list, wyszukiwać elementy listy zadań według kategorii i filtrować zadania według stanu ukończenia. Pobierz i przygotuj przykładową aplikację, wykonując czynności opisane w tej sekcji.

Pobieranie plików podstawowych

Aby skopiować repozytorium GitHub przykładowej aplikacji, uruchom to polecenie:

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

Po sklonowaniu repozytorium wykonaj te czynności, aby otworzyć je w Android Studio:

  1. W oknie Witamy w Android Studio kliknij Importuj projekt.
  2. Wybierz folder, do którego sklonowano repozytorium.

Możesz też wyświetlić wersję przykładowej aplikacji, która reprezentuje ukończone ćwiczenie z programowania, klonując gałąź codelab-complete repozytorium Github:

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

Aktualizowanie identyfikatora aplikacji na Androida

Aktualizacja identyfikatora aplikacji jednoznacznie identyfikuje aplikację na urządzeniu testowym i zapobiega wystąpieniu błędu „Zduplikowana nazwa pakietu”, jeśli aplikacja zostanie przesłana do Konsoli Play. Aby zaktualizować identyfikator aplikacji, otwórz app/build.gradle:

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

Zastąp „MYUNIQUENAME” w polu applicationId czymś unikalnym.

Dodawanie zależności interfejsu Shortcuts API

Dodaj do pliku zasobu app/build.gradle te biblioteki Jetpack:

app/build.gradle

dependencies {
   ...
   // Shortcuts library
   implementation "androidx.core:core:1.6.0"
   implementation 'androidx.core:core-google-shortcuts:1.0.1'
   ...
}

Testowanie aplikacji na urządzeniu

Zanim wprowadzisz kolejne zmiany w aplikacji, warto sprawdzić, co potrafi przykładowa aplikacja. Aby uruchomić aplikację na emulatorze, wykonaj te czynności:

  1. W Android Studio wybierz Uruchom > Uruchom aplikację lub na pasku narzędzi kliknij UruchomIkona uruchamiania aplikacji w Android Studio.
  2. W oknie Select Deployment Target (Wybierz miejsce docelowe wdrożenia) wybierz urządzenie i kliknij OK. Zalecana wersja systemu operacyjnego to Android 10 (poziom API 30) lub nowszy, chociaż akcje w aplikacji działają na urządzeniach z Androidem 5 (poziom API 21).
  3. Przytrzymaj przycisk ekranu głównego, aby skonfigurować Asystenta i sprawdzić, czy działa. Jeśli jeszcze tego nie zrobisz, musisz zalogować się w Asystencie na urządzeniu.

Więcej informacji o wirtualnych urządzeniach z Androidem znajdziesz w artykule Tworzenie wirtualnych urządzeń i zarządzanie nimi.

Przejrzyj aplikację, aby zobaczyć, co potrafi. Kliknięcie ikony plusa powoduje utworzenie nowego elementu zadania, a elementy menu w prawym górnym rogu umożliwiają wyszukiwanie i filtrowanie elementów zadań według stanu ukończenia.

4. Tworzenie klasy repozytorium skrótów

Kilka klas w naszej przykładowej aplikacji będzie wywoływać interfejs ShortcutManagerCompat API, aby przesyłać dynamiczne skróty i nimi zarządzać. Aby zmniejszyć nadmiarowość kodu, zaimplementujesz repozytorium, które umożliwi klasom projektu łatwe zarządzanie dynamicznymi skrótami.

Wzorzec repozytorium zapewnia przejrzysty interfejs API do zarządzania skrótami. Zaletą repozytorium jest to, że szczegóły bazowego interfejsu API są jednolicie abstrahowane za pomocą minimalnego interfejsu API. Aby wdrożyć repozytorium, wykonaj te czynności:

  1. Utwórz klasę ShortcutsRepository, aby wyodrębnić interfejs API ShortcutManagerCompat.
  2. Dodaj metody ShortcutsRepository do lokalizatora usług aplikacji.
  3. Zarejestruj usługę ShortcutRepository w głównej aplikacji.

Tworzenie repozytorium

Utwórz nową klasę Kotlin o nazwie ShortcutsRepository w pakiecie com.example.android.architecture.blueprints.todoapp.data.source. Ten pakiet znajdziesz w folderze app/src/main/java. Użyjesz tej klasy do zaimplementowania interfejsu udostępniającego minimalny zestaw metod obejmujących nasz przypadek użycia w ćwiczeniu w Codelabs.

Okno Androida Studio pokazujące lokalizację klasy ShortcutsRepository.

Rysunek 2. Okno plików projektu Android Studio z wyświetloną lokalizacją klasy ShortcutsRepository.

Wklej do nowej klasy ten kod:

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>) {
       //...
   }
}

Następnie zmodyfikuj metodę pushShortcut, aby wywoływała interfejs ShortcutManagerCompat API. Zaktualizuj klasę ShortcutsRepository tym kodem:

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

W przykładowym kodzie powyżej przekazaliśmy do interfejsu API wartość appContext. Jest to właściwość klasy zawierająca kontekst aplikacji. Aby uniknąć wycieków pamięci, ważne jest, aby używać kontekstu aplikacji (w przeciwieństwie do kontekstu aktywności), ponieważ kontekst może być przechowywany dłużej niż cykl życia aktywności hosta.

Dodatkowo interfejs API wymaga przekazania obiektu ShortcutInfoCompat dla obiektu Task. W powyższym przykładzie kodu osiągamy to, wywołując metodę prywatną createShortcutCompat, którą zaktualizujemy, aby utworzyć i zwrócić obiekt ShortcutInfoCompat. Aby to zrobić, zaktualizuj element createShortcutCompat za pomocą tego kodu:

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

Pozostałe stuby funkcji w tej klasie dotyczą aktualizowania i usuwania skrótów dynamicznych. Włącz te funkcje, aktualizując je za pomocą tego kodu:

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

Dodawanie klasy do lokalizatora usługi

Po utworzeniu klasy ShortcutsRepository następnym krokiem jest udostępnienie utworzonych obiektów tej klasy reszcie aplikacji. Aplikacja zarządza zależnościami klas, wdrażając wzorzec lokalizatora usług. Otwórz klasę lokalizatora usług za pomocą przeglądarki klas w Android Studio. W tym celu kliknij Nawigacja > Klasa i wpisz „ServiceLocator”. Kliknij utworzony plik Kotlin, aby otworzyć go w IDE.

U góry pliku ServiceLocator.kt wklej ten kod, aby zaimportować pakiety ShortcutsRepository i 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

Dodaj elementy usługi ShortcutRepository i metody, wklejając ten kod do treści pliku ServiceLocator.kt:

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

Zarejestruj usługę skrótu

Ostatnim krokiem jest zarejestrowanie nowej usługi ShortcutsRepository w aplikacji. W Android Studio otwórz plik TodoApplication.kt i skopiuj ten kod w górnej części pliku:

TodoApplication.kt

package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements

import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

Następnie zarejestruj usługę, dodając ten kod do treści klasy:

TodoApplication.kt

//...
class TodoApplication : Application() {

   //...

   val shortcutsRepository: ShortcutsRepository
       get() = ServiceLocator.provideShortcutsRepository(this)

   //...
}

Skompiluj aplikację i upewnij się, że nadal działa.

5. Wypchnij nowy skrót

Po utworzeniu usługi skrótów możesz zacząć przesyłać skróty. Użytkownicy generują w tej aplikacji treści (elementy zadań) i oczekują, że będą mogli do nich później wrócić. Dlatego umożliwimy dostęp do tych treści za pomocą głosu, przesyłając dynamiczny skrót powiązany z BII GET_THING za każdym razem, gdy użytkownik utworzy nowe zadanie. Dzięki temu Asystent może bezpośrednio uruchamiać żądany element zadania, gdy użytkownik wywoła BII, zadając pytania typu „OK Google, otwórz moją listę zakupów w aplikacji SampleApp”.

Aby włączyć tę funkcję w przykładowej aplikacji, wykonaj te czynności:

  1. Importowanie usługi ShortcutsRepository do klasy AddEditTaskViewModel, która odpowiada za zarządzanie obiektami listy zadań.
  2. Wysyłanie skrótu dynamicznego, gdy użytkownik tworzy nowe zadanie.

Importowanie repozytorium skrótów

Najpierw musimy udostępnić usługę ShortcutsRepositoryAddEditTaskViewModel. Aby to zrobić, zaimportuj usługę do ViewModelFactory, czyli klasy fabrycznej, której aplikacja używa do tworzenia instancji obiektów ViewModel, w tym AddEditTaskViewModel.

Otwórz przeglądarkę klas w Android Studio, klikając Nawigacja > Klasa i wpisując „ViewModelFactory”. Kliknij utworzony plik Kotlin, aby otworzyć go w IDE.

U góry pliku ViewModelFactory.kt wklej ten kod, aby zaimportować pakiety ShortcutsRepository i SuppressLint:

ViewModelFactory.kt

package com.example.android.architecture.blueprints.todoapp

// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

Następnie zastąp treść pliku ViewModelFactory tym kodem:

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
}

Zakończ ViewModelFactory zmiany, przechodząc o jeden poziom wyżej, i przekaż ShortcutsRepository do konstruktora fabryki. Otwórz przeglądarkę plików Android Studio, klikając Nawigacja > Plik i wpisując „FragmentExt.kt”. Kliknij powstały plik Kotlin w pakiecie util, aby otworzyć go w IDE.

Zastąp treść pliku FragmentExt.kt tym kodem:

fun Fragment.getViewModelFactory(): ViewModelFactory {
   val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
   val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
   return ViewModelFactory(taskRepository, shortcutsRepository, this)
}

Wysyłanie skrótu

Dzięki klasie abstrakcji ShortcutsRepository dostępnej dla klas ViewModel aplikacji przykładowej możesz zaktualizować klasę AddEditTaskViewModel, czyli klasę ViewModel odpowiedzialną za tworzenie notatek, aby za każdym razem, gdy użytkownik utworzy nową notatkę, wysyłać dynamiczny skrót.

W Android Studio otwórz przeglądarkę klas i wpisz „AddEditTaskViewModel”. Kliknij utworzony plik Kotlin, aby otworzyć go w IDE.

Najpierw dodaj do tej klasy pakiet ShortcutsRepository za pomocą tej instrukcji importu:

package com.example.android.architecture.blueprints.todoapp.addedittask

//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

Następnie dodaj właściwość klasy shortcutsRepository, aktualizując konstruktor klasy tym kodem:

AddEditTaskViewModel.kt

//...

/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
   private val tasksRepository: TasksRepository,
   private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {

    //...

Po dodaniu klasy ShortcutsRepository utwórz nową funkcję pushShortcut(), aby wywołać tę klasę. Wklej tę funkcję prywatną do treści pliku AddEditTaskViewModel:

AddEditTaskViewModel.kt

//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.pushShortcut(newTask)
}

Na koniec za każdym razem, gdy utworzysz zadanie, wyślij nowy skrót dynamiczny. Zastąp zawartość funkcji saveTask() tym kodem:

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

Testowanie kodu

Możemy wreszcie przetestować nasz kod. W tym kroku wypchniesz dynamiczny skrót z obsługą głosową i sprawdzisz go za pomocą aplikacji Asystent Google.

Tworzenie wersji przedpremierowej

Utworzenie podglądu za pomocą wtyczki Asystenta Google umożliwia wyświetlanie skrótów dynamicznych w Asystencie na urządzeniu testowym.

Instalowanie wtyczki testowej

Jeśli nie masz jeszcze wtyczki Asystenta Google, zainstaluj ją, wykonując te czynności w Android Studio:

  1. Kliknij **Plik > Ustawienia (Android Studio > Preferencje na macOS).
  2. W sekcji Wtyczki otwórz Marketplace i wyszukaj „Asystent Google”.
  3. Zainstaluj narzędzie i ponownie uruchom Androida Studio.

Tworzenie podglądu

Aby utworzyć podgląd, wykonaj te czynności w Android Studio:

  1. Kliknij Narzędzia > Asystent Google > „Narzędzie do testowania działań w aplikacji”.
  2. W polu Nazwa aplikacji wpisz nazwę, np. „Lista zadań”.
  3. Kliknij Utwórz podgląd. Jeśli pojawi się taka prośba, zapoznaj się z zasadami dotyczącymi akcji w aplikacji i warunkami korzystania z usługi i je zaakceptuj.

Okienko tworzenia podglądu w narzędziu do testowania akcji w aplikacji.

Rysunek 3. Panel podglądu tworzenia w narzędziu do testowania akcji w aplikacji.

Podczas testowania dynamiczne skróty, które przesyłasz do Asystenta, będą wyświetlane w Asystencie w kolejności określonej przez nazwę aplikacji podaną w podglądzie.

Przesyłanie i sprawdzanie skrótu

Uruchom ponownie aplikację przykładową na urządzeniu testowym i wykonaj te czynności :

  1. Utwórz nowe zadanie o nazwie „Start codelab”.
  2. Otwórz aplikację Asystent Google i powiedz lub wpisz „Moje skróty”.
  3. Kliknij kartę Odkrywaj. Powinien być widoczny przykładowy skrót.
  4. Kliknij skrót, aby go wywołać. Aplikacja powinna się uruchomić z nazwą skrótu wstępnie wypełnioną w polu filtra, co ułatwi znalezienie żądanego elementu zadania.

6. (Opcjonalnie) Aktualizowanie i usuwanie skrótu

Oprócz wysyłania nowych skrótów dynamicznych w czasie działania aplikacja może je aktualizować, aby odzwierciedlały bieżący stan treści i preferencji użytkownika. Dobrym rozwiązaniem jest aktualizowanie istniejących skrótów za każdym razem, gdy użytkownik zmodyfikuje element docelowy, np. zmieni nazwę zadania w naszej przykładowej aplikacji. Należy też usuwać odpowiedni skrót za każdym razem, gdy zasób docelowy zostanie usunięty, aby uniknąć wyświetlania użytkownikowi uszkodzonych skrótów.

Aktualizowanie skrótu

Modyfikuj AddEditTaskViewModel, aby aktualizować skrót dynamiczny za każdym razem, gdy użytkownik zmieni szczegóły elementu zadania. Najpierw zaktualizuj treść klasy, dodając ten kod, aby dodać funkcję aktualizacji, która korzysta z naszej klasy repozytorium:

AddEditTaskViewModel.kt

private fun updateShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.updateShortcuts(listOf(newTask))
}

Następnie zmodyfikuj funkcję saveTask() tak, aby wywoływała naszą nową metodę za każdym razem, gdy aktualizowane jest istniejące zadanie.

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

Przetestuj kod, ponownie uruchamiając aplikację i wykonując te czynności:

  1. Zmień nazwę istniejącego zadania na „Ukończ codelab”.
  2. Otwórz Asystenta Google, mówiąc „OK Google, moje skróty”.
  3. Kliknij kartę Odkrywaj. Powinna się wyświetlić zaktualizowana krótka etykieta skrótu testowego.

Usuwanie skrótu

Nasze skróty do przykładowych aplikacji powinny być usuwane, gdy użytkownik usunie zadanie. W przykładowej aplikacji logika usuwania zadań znajduje się w klasie TaskDetailViewModel. Zanim zaktualizujemy tę klasę, musimy ponownie zaktualizować ViewModelFactory, aby przekazać shortcutsRepository do TaskDetailViewModel.

Otwórz plik ViewModelFactory i zastąp zawartość metody konstruktora tym kodem:

//...
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
}

Następnie otwórz TaskDetailViewModel. Zaimportuj moduł ShortcutsRepository i zadeklaruj dla niego zmienną instancji, używając tego kodu:

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() {
...
}

Na koniec zmodyfikuj funkcję deleteTask() tak, aby wywoływała funkcję shortcutsRepository w celu usunięcia skrótu na podstawie jego identyfikatora za każdym razem, gdy zostanie usunięte zadanie z odpowiednim parametrem taskId:

TaskDetailViewModel.kt

fun deleteTask() = viewModelScope.launch {
   _taskId.value?.let {
       //...
       shortcutsRepository.removeShortcutsById(listOf(it))
   }
}

Aby przetestować kod, uruchom ponownie aplikację i wykonaj te czynności:

  1. Usuń zadanie testowe.
  2. Zmień nazwę istniejącego zadania na „Ukończ codelab”.
  3. Otwórz Asystenta Google, mówiąc „OK Google, moje skróty”.
  4. Kliknij kartę Odkrywaj. Sprawdź, czy skrót testowy już się nie wyświetla.

7. Dalsze kroki

Gratulacje! Dzięki temu użytkownicy naszej przykładowej aplikacji mogą łatwo wracać do utworzonych przez siebie notatek, zadając Asystentowi pytania takie jak „OK Google, otwórz moją listę zakupów w aplikacji ExampleApp”. Skróty zachęcają użytkowników do większego zaangażowania, ponieważ ułatwiają im ponowne odtwarzanie często używanych działań w aplikacji.

Omówione zagadnienia

Z tego modułu dowiedzieliśmy się, jak:

  • Określanie przypadków użycia dynamicznych skrótów w aplikacji.
  • Zmniejsz złożoność kodu za pomocą wzorców projektowych repozytorium, wstrzykiwania zależności i lokalizatora usług.
  • Wysyłaj dynamiczne skróty głosowe do treści aplikacji generowanych przez użytkowników.
  • Aktualizowanie i usuwanie dotychczasowych skrótów.

Co dalej

Możesz teraz wprowadzić dalsze ulepszenia w aplikacji Task List. Aby zobaczyć gotowy projekt, zapoznaj się z repozytorium –codelab-complete branch w GitHubie.

Oto kilka sugestii, które pomogą Ci dowiedzieć się więcej o rozszerzaniu tej aplikacji za pomocą akcji w aplikacji:

Aby kontynuować przygodę z Actions on Google, zapoznaj się z tymi materiałami:

Obserwuj nas na Twitterze @ActionsOnGoogle, aby być na bieżąco z najnowszymi ogłoszeniami. Możesz też użyć hashtagu #appActions, aby podzielić się tym, co udało Ci się stworzyć.

Ankieta do zbierania opinii

Na koniec wypełnij tę ankietę, aby podzielić się opinią na temat tego samouczka.