הרחבת קיצורי הדרך הדינמיים ל-Google Assistant באמצעות 'פעולות באפליקציה'

1. סקירה כללית

ב-Codelab הקודם, השתמשת בקיצורי דרך סטטיים כדי להטמיע אובייקטים מובְנים מסוג Intent (BII) נפוצים באפליקציה לדוגמה. מפתחי Android משתמשים ב'פעולות באפליקציה' כדי להרחיב את הפונקציונליות של האפליקציה ל-Google Assistant.

קיצורי דרך סטטיים משויכים לאפליקציה, ואפשר לעדכן אותם רק כשמפרסמים גרסאות חדשות של האפליקציה. ניתן להפעיל את הפונקציונליות הקולית לרכיבים דינמיים באפליקציה, כמו תוכן שנוצר על ידי משתמשים, באמצעות קיצורי דרך דינמיים. אפליקציות דוחפות קיצורי דרך דינמיים אחרי שהמשתמשים מבצעים פעולות רלוונטיות, כמו יצירת הערה חדשה באפליקציית מעקב אחרי משימות. באמצעות 'פעולות באפליקציה', מפעילים את קיצורי הדרך האלה לפקודות קוליות על ידי קישור שלהם ל-BII, כך שהמשתמשים יכולים לגשת לתוכן שלהם מ-Assistant ולומר, למשל, "Ok Google, open my shopping list on ExampleApp".

שלושה מסכים מסוג Progressive, שמוצג בהם Google Assistant מפעילה קיצור דרך דינמי.

איור 1. שלושה מסכים הדרגתיים שמוצגים בהם משימה שנוצרה על ידי משתמש, ו-Google Assistant מפעילה קיצור דרך דינמי לפריט הזה.

מה תפַתחו

ב-Codelab הזה, תפעילו קיצורי דרך דינמיים לקול באפליקציה לדוגמה של רשימת משימות ל-Android. כך המשתמשים יוכלו לבקש מ-Assistant לפתוח את הפריטים ברשימת המשימות שהם יוצרים באפליקציה. ניתן לעשות זאת באמצעות תבניות ארכיטקטורה של Android, במיוחד הדפוסים מאגר, מאתר השירות ו-ViewModel.

דרישות מוקדמות

ה-Codelab הזה מתבסס על המושגים של 'פעולות באפליקציה' שנלמדו בקוד Lab הקודם, במיוחד מזהי BII וקיצורי דרך סטטיים. אם עוד לא השתמשתם ב'פעולות באפליקציה', מומלץ להשלים את הפעולה הזו לפני שממשיכים.

בנוסף, לפני שממשיכים, צריך לוודא שבסביבת הפיתוח יש את ההגדרות הבאות:

  • טרמינל להרצת פקודות מעטפת עם git מותקן.
  • הגרסה היציבה האחרונה של Android Studio.
  • מכשיר Android פיזי או וירטואלי עם גישה לאינטרנט.
  • חשבון Google שמחובר ל-Android Studio, לאפליקציית Google ולאפליקציית Google Assistant.

2. איך זה עובד

כדי להפעיל קיצור דרך דינמי לגישה קולית באמצעות, יש לבצע את השלבים הבאים:

קיצורי דרך לקישור

כדי שקיצור דרך דינמי יהיה נגיש מ-Assistant, הוא צריך להיות מקושר ל-BII רלוונטי. כאשר מופעל BII עם קיצור דרך, Assistant מתאימה פרמטרים בבקשת המשתמש למילות מפתח שהוגדרו בקיצור הדרך. לדוגמה:

  • קיצור דרך שמקושר ל-BII של GET_THING יכול לאפשר למשתמשים לבקש תוכן ספציפי בתוך האפליקציה, ישירות מ-Assistant. * "Hey Google, open my shopping list on ExampleApp".
  • קיצור דרך שמקושר ל-BII של ORDER_MENU_ITEM עלול לאפשר למשתמשים לבצע מחדש הזמנות קודמות. * "Ok Google, order my regular from ExampleApp".

לרשימה מלאה של מזהי BII אפשר לעיין בחומר העזר בנושא כוונות מובנות.

מספקים קיצורי דרך ל-Assistant

אחרי קישור קיצורי הדרך ל-BII, השלב הבא הוא לאפשר ל-Assistant להטמיע את קיצורי הדרך האלה על ידי הוספת ספריית השילוב של Google קיצורי דרך לפרויקט. כשהספרייה הזאת תהיה זמינה, Assistant תזהה את כל מקשי הקיצור שהאפליקציה שלך מפעילה, וכך המשתמשים יוכלו להפעיל את קיצורי הדרך האלה באמצעות ביטוי הטריגר של קיצור הדרך ב-Assistant.

3. הכנת סביבת הפיתוח

ה-Codelab הזה משתמש בדוגמה של אפליקציה עם רשימת משימות שמיועדת ל-Android. באמצעות האפליקציה הזו, משתמשים יכולים להוסיף פריטים לרשימות, לחפש פריטים ברשימת המשימות לפי קטגוריה ולסנן משימות לפי סטטוס ההשלמה. ממלאים את הסעיף הזה כדי להוריד ולהכין את האפליקציה לדוגמה.

הורדת הקבצים הבסיסיים

מריצים את הפקודה הבאה כדי לשכפל את מאגר GitHub של האפליקציה לדוגמה:

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

אחרי שמשכפלים את המאגר, פועלים לפי השלבים הבאים כדי לפתוח אותו ב-Android Studio:

  1. בתיבת הדו-שיח תחילת העבודה ב-Android Studio לוחצים על ייבוא פרויקט.
  2. בוחרים את התיקייה שאליה שכפול המאגר.

לחלופין אפשר להציג גרסה של האפליקציה לדוגמה שמייצגת את ה-Codelab שהושלם על ידי שכפול ההסתעפות codelab-complete של מאגר ה-GitHub שלה:

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

עדכון המזהה של האפליקציה ל-Android

עדכון מזהה האפליקציה של האפליקציה משמש לזיהוי ייחודי של האפליקציה במכשיר הבדיקה ולמניעת 'שם חבילה כפול'. שגיאה אם האפליקציה הועלתה ל-Play Console. כדי לעדכן את מזהה האפליקציה, פותחים את app/build.gradle:

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

מחליפים את "MYUNIQUENAME" בשדה applicationId למשהו ייחודי לך.

הוספת יחסי תלות של קיצורי דרך ב-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הפעלת סמל האפליקציה ב-Android Studio בסרגל הכלים.
  2. בתיבת הדו-שיח Select Deployment Target בוחרים מכשיר ולוחצים על OK. הגרסה המומלצת של מערכת ההפעלה היא Android 10 (רמת API 30) ואילך, אבל 'פעולות באפליקציה' פועלת במכשירים בגרסת Android 5 (רמת API 21).
  3. כדי להגדיר את Assistant ולוודא שהיא פועלת, לוחצים לחיצה ארוכה על הלחצן הראשי. אם עדיין לא עשית זאת, יהיה עליך להיכנס אל Assistant במכשיר שלך.

מידע נוסף על מכשירים וירטואליים של Android זמין במאמר יצירה וניהול של מכשירים וירטואליים.

בדקו בקצרה את האפליקציה כדי לראות מה היא יכולה לעשות. הקשה על סמל הפלוס יוצרת פריט חדש במשימה, ובעזרת האפשרויות בתפריט בפינה השמאלית העליונה אפשר לחפש ולסנן את המשימות לפי סטטוס ההשלמה.

4. יצירת מחלקה למאגר קיצורי דרך

חלק מהכיתות באפליקציה לדוגמה שלנו יקראו ל-API של ShortcutManagerCompat כדי להעביר ולנהל קיצורי דרך דינמיים. כדי לצמצם את יתירות הקוד, תטמיעו מאגר כדי לאפשר למחלקות הפרויקטים לנהל בקלות קיצורי דרך דינמיים.

תבנית העיצוב של מאגר מספקת API נקי לניהול קיצורי דרך. היתרון של מאגר הוא שהפרטים של ה-API הבסיסי מופשטים באופן אחיד מאחורי API מינימלי. כדי להטמיע את המאגר:

  1. יוצרים מחלקה ShortcutsRepository כדי להפשט את ה-API של ShortcutManagerCompat.
  2. צריך להוסיף methods של ShortcutsRepository למאתר השירות של האפליקציה.
  3. רישום השירות ShortcutRepository באפליקציה הראשית.

יצירת המאגר

יוצרים כיתת Kotlin חדשה בשם ShortcutsRepository בחבילה com.example.android.architecture.blueprints.todoapp.data.source. החבילה הזו מאורגנת בתיקייה app/src/main/java. השיעור הזה ישמש אתכם כדי להטמיע ממשק שמספק קבוצה מינימלית של שיטות שמכסות את התרחיש לדוגמה שלנו ב-Codelab.

חלון Android Studio שמציג את המיקום של המחלקה ShortcutsRepository.

איור 2. חלון של קובצי פרויקט ב-Android Studio שמוצג בו מיקום המחלקה של 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>) {
       //...
   }
}

בשלב הבא, מעדכנים את ה-method pushShortcut כדי להפעיל את ה-API של ShortcutManagerCompat. מעדכנים את הכיתה 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 דורש שנעביר אובייקט ShortcutInfoCompat עבור אובייקט המשימה. בדוגמת הקוד הקודמת, ניתן לעשות זאת באמצעות קריאה לשיטה הפרטית createShortcutCompat, שאותה נעדכן כדי ליצור ולהחזיר אובייקט ShortcutInfoCompat. כדי לעשות זאת, צריך לעדכן את ה-stub של 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()
}

שאר ה-stubs של הפונקציות בכיתה הזו עוסקים בעדכון ובמחיקה של קיצורי דרך דינמיים. כדי להפעיל את הפונקציות האלה, צריך לעדכן אותן באמצעות הקוד הבא:

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, עוברים אל ניווט > 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

מוסיפים את רכיבי השירות ואת ה-methods ShortcutRepository על ידי הדבקת הקוד הבא בגוף של 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)
       }
   }
 }

רישום השירות של קיצורי הדרך

השלב האחרון הוא רישום של שירות 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. העברת קיצור דרך חדש בדחיפה

אחרי יצירת השירות לקיצורי הדרך, ניתן להתחיל להעביר קיצורי דרך. משתמשים יוצרים תוכן (פריטי משימה) באפליקציה הזו ומצפים שיוכלו לחזור אליהם מאוחר יותר, לכן כדי להפעיל את הגישה לתוכן הזה באופן קולי, נשלח קיצור דרך דינמי שמקושר ל-BII GET_THING בכל פעם שמשתמש יוצר משימה חדשה. כך Assistant יכולה להפעיל את המשתמשים ישירות לפריט המשימה המבוקש כשהם מפעילים את ה-BII באמצעות פקודות כמו "Ok Google, open my shopping list on SampleApp".

כדי להפעיל את הפונקציונליות הזו באפליקציה לדוגמה, מבצעים את השלבים הבאים:

  1. ייבוא של השירות ShortcutsRepository למחלקה AddEditTaskViewModel, שאחראי על ניהול אובייקטים של רשימות משימות.
  2. דחיפת קיצור דרך דינמי כשהמשתמש יוצר משימה חדשה.

ייבוא של ShortcutsRepository

קודם אנחנו צריכים להפוך את השירות ShortcutsRepository לזמין עבור AddEditTaskViewModel. כדי לעשות זאת, מייבאים את השירות אל ViewModelFactory, רמת היצרן שהאפליקציה משתמשת בה כדי ליצור אובייקטים של ViewModel, כולל AddEditTaskViewModel.

פותחים את דפדפן הכיתה ב-Android Studio בקטע ניווט > כיתה וההקלדה של "ViewModel חוקיים". לוחצים על קובץ ה-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 ל-constructor של המפעל. פותחים את הדפדפן לקבצים של Android Studio על ידי מעבר אל ניווט > קובץ מקלידים "FragmentExt.kt". לוחצים על קובץ ה-Kotlin שנוצר בחבילת ה-util כדי לפתוח אותו בסביבת הפיתוח המשולבת (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)
}

לחיצה על קיצור דרך

כשסיווג ההפשטה ShortcutsRepository זמין לכיתות ViewModel של האפליקציה לדוגמה, אתם מעדכנים את 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 על ידי עדכון ה-constructor של המחלקה בקוד הבא:

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 Assistant.

יצירת קטע מקדים

יצירת תצוגה מקדימה באמצעות הפלאגין של Google Assistant מאפשרת לקיצורי הדרך הדינמיים להופיע ב-Assistant במכשיר הבדיקה.

התקנת הפלאגין לבדיקה

אם עדיין לא התקנתם את הפלאגין של Google Assistant, צריך לבצע את הפעולות הבאות ב-Android Studio כדי להתקין אותו:

  1. מעבר אל **קובץ > 'הגדרות' (Android Studio > 'העדפות' ב-MacOS).
  2. בקטע יישומי פלאגין, עוברים אל Marketplace ומחפשים את 'Google Assistant'.
  3. מתקינים את הכלי ומפעילים מחדש את Android Studio.

יצירת התצוגה המקדימה

כדי ליצור תצוגה מקדימה, מבצעים את השלבים הבאים ב-Android Studio:

  1. לוחצים על כלים > Google Assistant > "כלי הבדיקה של פעולות באפליקציה".
  2. בתיבה שם האפליקציה, מגדירים שם כמו "רשימת משימות".
  3. לוחצים על יצירת תצוגה מקדימה. אם מופיעה בקשה, קוראים את המדיניות ואת התנאים וההגבלות של 'פעולות באפליקציה' ומאשרים אותם.

חלונית ליצירת תצוגה מקדימה של App Actions Test Tool.

איור 3. החלונית ליצירת תצוגה מקדימה של App Actions Test Tool.

במהלך הבדיקה, קיצורי דרך דינמיים שלוחצים על ה-Assistant מוצגים ב-Assistant לפי שם האפליקציה שסיפקתם בשביל התצוגה המקדימה.

דחיפת קיצור דרך ובדיקה שלו

מפעילים מחדש את האפליקציה לדוגמה במכשיר הבדיקה ומבצעים את השלבים הבאים :

  1. יוצרים משימה חדשה בשם 'Start Codelab'
  2. פותחים את אפליקציית Google Assistant ואומרים או מקלידים: "My shortcuts" (הקיצורי דרך שלי).
  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. כדי לפתוח את Google Assistant, אומרים "Ok Google, my shortcuts".
  3. מקישים על הכרטיסייה מה חדש. אמורה להופיע תווית קצרה מעודכנת של קיצור הדרך לבדיקה.

הסרת קיצור דרך

אנחנו מסירים את הדוגמאות שלנו לקיצורי דרך של אפליקציות בכל פעם שמשתמש מוחק משימה. באפליקציה לדוגמה, הלוגיקה של מחיקת המשימה נמצאת במחלקה TaskDetailViewModel. לפני שנעדכן את הכיתה הזו, עלינו לעדכן שוב את ההרשאה ViewModelFactory כדי להעביר את shortcutsRepository אל TaskDetailViewModel.

פותחים את ViewModelFactory ומחליפים את תוכן ה-method של ה-constructor בקוד הבא:

//...
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 תואמת:

TaskDetailViewModel.kt

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

כדי לבדוק את הקוד, צריך להפעיל מחדש את האפליקציה ולפעול לפי השלבים הבאים:

  1. מוחקים את משימת הבדיקה.
  2. משנים את השם של פריט המשימה הקיים ל-Finish Codelab.
  3. כדי לפתוח את Google Assistant, אומרים "Ok Google, my shortcuts".
  4. מקישים על הכרטיסייה מה חדש. מוודאים שקיצור הדרך לבדיקה לא מופיע יותר.

7. השלבים הבאים

מזל טוב! בזכותך, משתמשי האפליקציה לדוגמה שלנו יכולים לחזור בקלות לפתקים שהם יצרו ולבקש מ-Assistant, למשל: "Ok Google, open my shopping list on ExampleApp". קיצורי דרך מעודדים מעורבות עמוקה יותר של המשתמשים כי הם מאפשרים למשתמשים לחזור בקלות על פעולות שהם עשו באפליקציה שלכם לעיתים קרובות.

אילו נושאים דיברנו?

ב-Codelab הזה למדת איך:

  • לזהות תרחישים לדוגמה של דחיפת קיצורי דרך דינמיים באפליקציה.
  • הפחתת את המורכבות של הקוד באמצעות דפוסי עיצוב של מאגר, החדרת תלות ותבניות תכנון של מאתר שירות (service locator).
  • דחיפת קיצורי דרך דינמיים שמופעלים באמצעות קול לתוכן אפליקציה שנוצר על ידי משתמשים.
  • לעדכן ולהסיר את קיצורי הדרך הקיימים.

מה השלב הבא?

מכאן אפשר לנסות לבצע שיפורים נוספים באפליקציה 'רשימת משימות'. כדי להפנות לפרויקט המוגמר, ראו הסתעפות Codelab-complete במאגר GitHub.

בהמשך מופיעות כמה הצעות ללמידה נוספת בנוגע להרחבת האפליקציה הזו באמצעות 'פעולות באפליקציה':

כדי להמשיך בתהליך שלך ב-Actions on Google, כדאי לעיין במקורות המידע הבאים:

אפשר לעקוב אחרינו ב- Twitter @ActionsOnGoogle כדי להתעדכן בהכרזות האחרונות, ולשלוח ציוץ אל #appActions כדי לשתף את מה שפיתחתם!

סקר משוב

לסיום, נמלא את הסקר הזה כדי לשלוח משוב על החוויה שלך עם Codelab.