میانبرهای پویا را به دستیار Google با اقدامات برنامه گسترش دهید

۱. مرور کلی

در آزمایشگاه کد قبلی ، از میانبرهای استاتیک برای پیاده‌سازی intentهای داخلی (BII) پرکاربرد در یک برنامه نمونه استفاده کردید. توسعه‌دهندگان اندروید از App Actions برای گسترش قابلیت‌های برنامه به دستیار گوگل استفاده می‌کنند.

میانبرهای استاتیک با یک برنامه همراه هستند و فقط با انتشار نسخه‌های جدید برنامه می‌توانند به‌روزرسانی شوند. فعال کردن قابلیت صوتی برای عناصر پویا در یک برنامه، مانند محتوای تولید شده توسط کاربر، با استفاده از میانبرهای پویا حاصل می‌شود. برنامه‌ها پس از انجام اقدامات مرتبط توسط کاربران، مانند ایجاد یک یادداشت جدید در یک برنامه ردیابی وظیفه، میانبرهای پویا را ارائه می‌دهند. با App Actions، شما این میانبرها را با اتصال آنها به یک BII برای صدا فعال می‌کنید و به کاربران این امکان را می‌دهید که با گفتن چیزهایی مانند "سلام گوگل، لیست خرید من را در ExampleApp باز کن" از طریق دستیار به محتوای خود دسترسی پیدا کنند.

سه صفحه نمایش پیش‌رونده که دستیار گوگل را در حال اجرای یک میانبر پویا نشان می‌دهند.

شکل ۱. سه صفحه نمایش پیش‌رونده که یک وظیفه ایجاد شده توسط کاربر را نشان می‌دهند و دستیار گوگل در حال اجرای یک میانبر پویا برای آن مورد وظیفه است.

آنچه خواهید ساخت

در این آزمایشگاه کد، شما میانبرهای پویا برای صدا را در یک برنامه اندروید نمونه لیست کارها فعال خواهید کرد، که به کاربران این امکان را می‌دهد تا از دستیار بخواهند موارد لیست وظایفی را که در برنامه ایجاد می‌کنند، باز کند. شما این کار را با استفاده از الگوهای معماری اندروید، به ویژه الگوهای repository ، service locator و ViewModel انجام می‌دهید.

پیش‌نیازها

این آزمایشگاه کد بر اساس مفاهیم App Actions که در آزمایشگاه کد قبلی پوشش داده شده است، به ویژه BII ها و میانبرهای استاتیک، ساخته شده است. اگر در App Actions تازه کار هستید، توصیه می‌کنیم قبل از ادامه، آن آزمایشگاه کد را تکمیل کنید.

علاوه بر این، قبل از ادامه، مطمئن شوید که محیط توسعه شما پیکربندی زیر را دارد:

  • یک ترمینال برای اجرای دستورات shell با نصب git.
  • آخرین نسخه پایدار اندروید استودیو .
  • یک دستگاه اندروید فیزیکی یا مجازی با دسترسی به اینترنت.
  • یک حساب گوگل که با آن به اندروید استودیو، برنامه گوگل و برنامه دستیار گوگل وارد شده باشید.

۲. نحوه‌ی کار آن را درک کنید

فعال کردن یک میانبر پویا برای دسترسی صوتی شامل مراحل زیر است:

  • اتصال یک میانبر پویا به یک BII واجد شرایط.
  • فعال کردن دستیار برای دریافت میانبرها با افزودن کتابخانه ادغام میانبرهای گوگل .
  • فشردن یک میانبر هر زمان که کاربر وظیفه درون‌برنامه‌ای مربوطه را انجام می‌دهد.

میانبرهای اتصال

برای اینکه یک میانبر پویا از طریق دستیار قابل دسترسی باشد، باید به یک BII مرتبط متصل شود. وقتی یک BII با میانبر فعال می‌شود، دستیار پارامترهای موجود در درخواست کاربر را با کلمات کلیدی تعریف شده در میانبر متصل مطابقت می‌دهد. برای مثال:

  • یک میانبر متصل به GET_THING BII می‌تواند به کاربران اجازه دهد محتوای درون‌برنامه‌ای خاصی را مستقیماً از دستیار گوگل درخواست کنند. * "سلام گوگل، لیست خرید من را در ExampleApp باز کن."
  • یک میانبر متصل به START_EXERCISE BII می‌تواند به کاربران اجازه دهد جلسات تمرین خود را ببینند. * "سلام گوگل، از ExampleApp بخواه که تمرین معمول من را شروع کند."

برای فهرست کامل و طبقه‌بندی‌شده‌ی BIIها، به مرجع Intentهای داخلی مراجعه کنید.

ارائه میانبرها به دستیار

پس از اتصال میانبرهای خود به یک BII، مرحله بعدی این است که با اضافه کردن کتابخانه Google Shortcuts Integration به پروژه خود، دستیار را قادر به دریافت این میانبرها کنید. با وجود این کتابخانه، دستیار از هر میانبری که توسط برنامه شما ارسال می‌شود آگاه خواهد بود و کاربران را قادر می‌سازد تا با استفاده از عبارت فعال‌سازی میانبر در دستیار، آن میانبرها را اجرا کنند.

۳. محیط توسعه خود را آماده کنید

این codelab از یک برنامه نمونه لیست کارها که برای اندروید ساخته شده است استفاده می‌کند. با استفاده از این برنامه، کاربران می‌توانند مواردی را به لیست‌ها اضافه کنند، موارد لیست کارها را بر اساس دسته‌بندی جستجو کنند و کارها را بر اساس وضعیت تکمیل فیلتر کنند. با تکمیل این بخش، برنامه نمونه را دانلود و آماده کنید.

فایل‌های پایه خود را دانلود کنید

دستور زیر را برای کپی کردن مخزن گیت‌هاب برنامه نمونه اجرا کنید:

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

پس از کلون کردن مخزن، برای باز کردن آن در اندروید استودیو، این مراحل را دنبال کنید:

  1. در پنجره‌ی «به اندروید استودیو خوش آمدید» ، روی «وارد کردن پروژه» کلیک کنید.
  2. پوشه‌ای را که مخزن را در آن کلون کرده‌اید، انتخاب کنید.

از طرف دیگر، می‌توانید با کپی کردن شاخه codelab-complete از مخزن گیت‌هاب آن، نسخه‌ای از برنامه نمونه را که نشان‌دهنده codelab تکمیل‌شده است، مشاهده کنید:

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

به‌روزرسانی شناسه برنامه اندروید

به‌روزرسانی شناسه برنامه، برنامه را به‌طور منحصربه‌فرد روی دستگاه آزمایشی شما شناسایی می‌کند و در صورت آپلود برنامه در کنسول Play، از خطای "نام بسته تکراری" جلوگیری می‌کند. برای به‌روزرسانی شناسه برنامه، app/build.gradle را باز کنید:

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

عبارت "MYUNIQUENAME" را در فیلد applicationId با چیزی که مختص خودتان باشد جایگزین کنید.

وابستگی‌های API میانبرها را اضافه کنید

کتابخانه‌های Jetpack زیر را به فایل منبع app/build.gradle اضافه کنید:

برنامه/ساخت.gradle

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

برنامه را روی دستگاه خود آزمایش کنید

قبل از ایجاد تغییرات بیشتر در برنامه، بهتر است ایده‌ای از قابلیت‌های برنامه نمونه داشته باشید. برای اجرای برنامه روی شبیه‌ساز خود، این مراحل را دنبال کنید:

  1. در اندروید استودیو، گزینه Run > Run app را انتخاب کنید یا روی Run کلیک کنید. اجرای آیکون برنامه در اندروید استودیو در نوار ابزار.
  2. در پنجره‌ی «انتخاب هدف استقرار» ، دستگاهی را انتخاب کرده و روی «تأیید» کلیک کنید. نسخه‌ی سیستم عامل پیشنهادی، اندروید ۱۰ (سطح API 30) یا بالاتر است، اگرچه «اقدامات برنامه» روی دستگاه‌هایی با اندروید ۵ (سطح API 21) نیز کار می‌کند.
  3. برای تنظیم دستیار و تأیید صحت عملکرد آن، دکمه صفحه اصلی را فشار داده و نگه دارید. اگر قبلاً وارد دستیار در دستگاه خود نشده‌اید، باید وارد آن شوید.

برای اطلاعات بیشتر در مورد دستگاه‌های مجازی اندروید، به ایجاد و مدیریت دستگاه‌های مجازی مراجعه کنید.

به طور خلاصه برنامه را بررسی کنید تا ببینید چه کارهایی می‌تواند انجام دهد. ضربه زدن روی نماد به علاوه یک مورد کار جدید ایجاد می‌کند و موارد منو در بالا سمت راست به شما امکان می‌دهد موارد کار را بر اساس وضعیت تکمیل جستجو و فیلتر کنید.

۴. یک کلاس مخزن میانبر ایجاد کنید

چندین کلاس در برنامه نمونه ما، API مربوط به ShortcutManagerCompat را برای ارسال و مدیریت میانبرهای پویا فراخوانی می‌کنند. برای کاهش افزونگی کد، یک مخزن (repository) پیاده‌سازی خواهید کرد تا کلاس‌های پروژه شما بتوانند به راحتی میانبرهای پویا را مدیریت کنند.

الگوی طراحی مخزن، یک API تمیز برای مدیریت میانبرها ارائه می‌دهد. مزیت مخزن این است که جزئیات API اصلی به طور یکنواخت در پشت یک API مینیمال خلاصه شده‌اند. مخزن را با دنبال کردن این مراحل پیاده‌سازی کنید:

  1. یک کلاس ShortcutsRepository ایجاد کنید تا ShortcutManagerCompat API را انتزاعی (abstract) کند.
  2. متدهای ShortcutsRepository را به مکان‌یاب سرویس برنامه اضافه کنید.
  3. سرویس ShortcutRepository را در برنامه اصلی ثبت کنید.

مخزن را ایجاد کنید

یک کلاس کاتلین جدید با نام ShortcutsRepository در پکیج com.example.android.architecture.blueprints.todoapp.data.source ایجاد کنید. می‌توانید این پکیج را به صورت سازماندهی شده در پوشه app/src/main/java پیدا کنید. شما از این کلاس برای پیاده‌سازی یک رابط کاربری استفاده خواهید کرد که مجموعه‌ای حداقلی از متدها را برای پوشش مورد استفاده ما در codelab ارائه می‌دهد.

پنجره اندروید استودیو محل کلاس ShortcutsRepository را نشان می‌دهد.

شکل 2. پنجره‌ی فایل‌های پروژه‌ی اندروید استودیو که محل کلاس 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 را برای فراخوانی 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 ارسال کردیم. این یک ویژگی کلاس است که Application Context را در خود نگه می‌دارد. استفاده از Application Context (برخلاف Activity Context ) برای جلوگیری از نشت حافظه مهم است، زیرا ممکن است context مدت بیشتری نسبت به چرخه حیات activity میزبان حفظ شود.

علاوه بر این، API نیاز دارد که ما یک شیء ShortcutInfoCompat را برای شیء Task ارسال کنیم. در نمونه کد قبلی، ما این کار را با فراخوانی متد خصوصی 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 ، مرحله بعدی در دسترس قرار دادن اشیاء نمونه‌سازی شده از این کلاس برای بقیه برنامه است. این برنامه با پیاده‌سازی الگوی locator سرویس ، وابستگی‌های کلاس را مدیریت می‌کند. کلاس locator سرویس را با استفاده از مرورگر کلاس در اندروید استودیو، با رفتن به 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)
       }
   }
 }

سرویس میانبر را ثبت کنید

مرحله آخر، ثبت سرویس ShortcutsRepository جدید خود در برنامه است. در اندروید استودیو، 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)

   //...
}

برنامه را بسازید و مطمئن شوید که همچنان اجرا می‌شود.

۵. یک میانبر جدید ایجاد کنید

با ایجاد سرویس میانبر، آماده‌اید تا شروع به ارسال میانبرها کنید. از آنجایی که کاربران در این برنامه محتوا (آیتم‌های وظیفه) تولید می‌کنند و انتظار دارند بعداً بتوانند به آنها بازگردند، ما با ارسال یک میانبر پویا که به GET_THING BII هر بار که کاربر یک وظیفه جدید ایجاد می‌کند، متصل است، دسترسی به این محتوا را به صورت صوتی فعال می‌کنیم. این امر به دستیار گوگل اجازه می‌دهد تا کاربران را مستقیماً به آیتم وظیفه درخواستی خود هدایت کند، زمانی که BII را با پرسیدن چیزهایی مانند " سلام گوگل، لیست خرید من را در SampleApp باز کن" فعال می‌کنند.

شما می‌توانید با انجام این مراحل، این قابلیت را در برنامه نمونه فعال کنید:

  1. وارد کردن سرویس ShortcutsRepository به کلاس AddEditTaskViewModel ، که مسئول مدیریت اشیاء لیست وظایف است.
  2. فشردن یک میانبر پویا هنگام ایجاد یک وظیفه جدید توسط کاربر.

وارد کردن مخزن میانبرها

ابتدا باید سرویس ShortcutsRepository را برای AddEditTaskViewModel در دسترس قرار دهیم. برای انجام این کار، سرویس را به ViewModelFactory ، کلاس factory که برنامه برای نمونه‌سازی اشیاء ViewModel ، از جمله AddEditTaskViewModel استفاده می‌کند، وارد کنید.

با رفتن به مسیر Navigate > Class و تایپ عبارت "ViewModelFactory" در اندروید استودیو، مرورگر کلاس را باز کنید. روی فایل کاتلین حاصل کلیک کنید تا در 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 را به سازنده‌ی factory ارسال کنید. با رفتن به Navigate > File و تایپ "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 مسئول ایجاد یادداشت‌ها، را به‌روزرسانی می‌کنید تا هر بار که کاربر یادداشت جدیدی ایجاد می‌کند، یک میانبر پویا اضافه کند.

در اندروید استودیو، مرورگر کلاس را باز کنید و عبارت "AddEditTaskViewModel" را تایپ کنید. روی فایل کاتلین حاصل کلیک کنید تا در IDE شما باز شود.

ابتدا، پکیج ShortcutsRepository را با استفاده از دستور import زیر به این کلاس اضافه کنید:

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

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

در مرحله بعد، با به‌روزرسانی سازنده کلاس با کد زیر، ویژگی کلاس shortcutsRepository را اضافه کنید:

افزودنویرایشTaskViewModel.kt

//...

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

    //...

با اضافه شدن کلاس ShortcutsRepository ، یک تابع جدید به نام pushShortcut() ایجاد کنید تا این کلاس را فراخوانی کند. تابع خصوصی زیر را در بدنه AddEditTaskViewModel قرار دهید:

افزودنویرایشTaskViewModel.kt

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

در نهایت، هر زمان که یک وظیفه ایجاد می‌شود، یک میانبر پویای جدید اعمال کنید. محتویات تابع saveTask() را با کد زیر جایگزین کنید:

افزودنویرایشTaskViewModel.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)
    }
}

کد خود را آزمایش کنید

بالاخره آماده‌ایم تا کد خود را آزمایش کنیم! در این مرحله، شما یک میانبر پویای صوتی را فشار می‌دهید و با استفاده از برنامه دستیار گوگل آن را بررسی می‌کنید.

ایجاد پیش‌نمایش

ایجاد پیش‌نمایش با استفاده از افزونه‌ی دستیار گوگل، امکان نمایش میانبرهای پویای شما را در دستیار دستگاه آزمایشی‌تان فراهم می‌کند.

افزونه تست را نصب کنید

اگر افزونه‌ی دستیار گوگل را از قبل ندارید، با دنبال کردن این مراحل در اندروید استودیو آن را نصب کنید:

  1. به مسیر **File > Settings (در مک او اس، اندروید استودیو > Preferences) بروید.
  2. در بخش افزونه‌ها ، به بازار بروید و عبارت «دستیار گوگل» را جستجو کنید.
  3. ابزار را نصب کنید و اندروید استودیو را مجدداً راه اندازی کنید.

پیش‌نمایش را ایجاد کنید

با دنبال کردن این مراحل در اندروید استودیو، پیش‌نمایشی ایجاد کنید:

  1. روی ابزارها > دستیار گوگل > « ابزار تست اقدامات برنامه » کلیک کنید.
  2. در کادر نام برنامه ، نامی مانند "لیست کارها" (Todo List) تعریف کنید.
  3. روی ایجاد پیش‌نمایش کلیک کنید. در صورت درخواست، خط‌مشی‌ها و شرایط خدمات «عملکردهای برنامه» را مرور و بپذیرید.

پنجره ایجاد پیش‌نمایش ابزار تست اقدامات برنامه.

شکل ۳. پنجره ایجاد پیش‌نمایش ابزار تست اقدامات برنامه.

در طول آزمایش، میانبرهای پویایی که به دستیار وارد می‌کنید، در دستیار بر اساس نام برنامه‌ای که برای پیش‌نمایش ارائه کرده‌اید، نمایش داده می‌شوند.

یک میانبر را فشار دهید و بررسی کنید

برنامه نمونه را در دستگاه آزمایشی خود مجدداً اجرا کنید و مراحل زیر را انجام دهید:

  1. یک وظیفه جدید با عنوان "شروع codelab" ایجاد کنید
  2. برنامه دستیار گوگل را باز کنید و عبارت «میانبرهای من» را بگویید یا تایپ کنید.
  3. روی برگه «کاوش» ضربه بزنید. باید میانبر نمونه را ببینید.
  4. برای فراخوانی میانبر، روی آن ضربه بزنید. باید ببینید که برنامه با نام میانبر که از قبل در کادر فیلتر قرار داده شده است، اجرا می‌شود و پیدا کردن مورد درخواستی را آسان می‌کند.

۶. (اختیاری) به‌روزرسانی و حذف یک میانبر

علاوه بر ارسال میانبرهای پویای جدید در زمان اجرا، برنامه شما می‌تواند آنها را به‌روزرسانی کند تا وضعیت فعلی محتوا و تنظیمات کاربر را منعکس کند. به‌روزرسانی میانبرهای موجود هر زمان که کاربر آیتم مقصد را تغییر می‌دهد، مانند تغییر نام یک وظیفه در برنامه نمونه ما، رویه خوبی است. همچنین باید هر زمان که منبع مقصد حذف می‌شود، میانبر مربوطه را حذف کنید تا از نمایش میانبرهای خراب به کاربر جلوگیری شود.

به‌روزرسانی یک میانبر

AddEditTaskViewModel طوری تغییر دهید که هر زمان کاربر جزئیات یک آیتم وظیفه را تغییر داد، یک میانبر پویا به‌روزرسانی شود. ابتدا، بدنه کلاس را با کد زیر به‌روزرسانی کنید تا یک تابع به‌روزرسانی که از کلاس مخزن ما استفاده می‌کند، اضافه شود:

افزودنویرایشTaskViewModel.kt

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

در مرحله بعد، تابع saveTask() را طوری تغییر دهید که هر زمان یک وظیفه موجود به‌روزرسانی می‌شود، متد جدید ما را فراخوانی کند.

افزودنویرایشTaskViewModel.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. عنوان مورد وظیفه فعلی خود را به «پایان کدنویسی» تغییر دهید.
  2. با گفتن «هی گوگل، میانبرهای من» دستیار گوگل را باز کنید.
  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 مربوطه حذف می‌شود، یک میانبر را بر اساس شناسه آن حذف کند:

TaskDetailViewModel.kt

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

برای آزمایش کد خود، برنامه را مجدداً راه‌اندازی کنید و این مراحل را دنبال کنید:

  1. تکلیف آزمایشی خود را حذف کنید.
  2. عنوان مورد وظیفه فعلی خود را به «پایان کدنویسی» تغییر دهید.
  3. با گفتن «هی گوگل، میانبرهای من» دستیار گوگل را باز کنید.
  4. روی برگه «کاوش» ضربه بزنید. تأیید کنید که میانبر آزمایشی شما دیگر نمایش داده نمی‌شود.

۷. مراحل بعدی

تبریک! به لطف شما، کاربران برنامه نمونه ما می‌توانند به راحتی با پرسیدن چیزهایی از دستیار گوگل مانند «سلام گوگل، لیست خرید من را در ExampleApp باز کن» به یادداشت‌هایی که ایجاد کرده‌اند، بازگردند. میانبرها با آسان کردن بازپخش اقدامات متداول در برنامه شما، تعامل عمیق‌تر کاربر را تشویق می‌کنند.

آنچه ما پوشش داده‌ایم

در این آزمایشگاه کد، شما یاد گرفتید که چگونه:

  • موارد استفاده از قرار دادن میانبرهای پویا در یک برنامه را مشخص کنید.
  • کاهش پیچیدگی کد با استفاده از الگوهای طراحی مخزن، تزریق وابستگی و مکان‌یاب سرویس.
  • میانبرهای پویای صوتی را به محتوای برنامه تولید شده توسط کاربر فشار دهید.
  • به‌روزرسانی و حذف میانبرهای موجود.

قدم بعدی چیست؟

از اینجا، می‌توانید اصلاحات بیشتری را در برنامه Task List خود انجام دهید. برای ارجاع به پروژه نهایی، به شاخه repo –codelab-complete در GitHub مراجعه کنید.

در اینجا چند پیشنهاد برای یادگیری بیشتر در مورد گسترش این برنامه با App Actions ارائه شده است:

برای ادامه سفر «اقدامات در گوگل» خود، این منابع را بررسی کنید:

برای اطلاع از آخرین اطلاعیه‌های ما، ما را در توییتر با شناسه @ActionsOnGoogle دنبال کنید و برای به اشتراک گذاشتن دستاوردهای خود، در توییتر با هشتگ #appActions توییت کنید!

نظرسنجی بازخورد

در نهایت، لطفاً این نظرسنجی را پر کنید تا در مورد تجربه خود با این آزمایشگاه کد، بازخورد خود را ارائه دهید.