整合應用程式動作與 Android 小工具

圖 1. 示例:系統啟動了 GET_EXERCISE_OBSERVATION 的小工具。

對許多意圖來說,最好的回應方式就是提供使用者簡單的答案、簡短的確認訊息,或是快速的互動體驗。您可以在 Google 助理中顯示 Android 應用程式小工具,藉此執行這類意圖。

本指南會說明如何使用小工具執行 Google 助理使用者查詢內容,以及如何使用應用程式動作小工具擴充功能程式庫加強 Google 助理的小工具使用體驗。

優點

小工具是小型的應用程式檢視畫面,您可以內嵌到 Android 的介面途徑中,如啟動器或鎖定螢幕。只要善加運用「應用程式動作」,您的小工具就能顯示在 Google 助理中,發揮更好的效果。

  1. 探索:主動在回應使用者自然語言查詢時顯示小工具。
  2. 參與:在免持情境下顯示小工具,例如當 Google 助理在鎖定畫面或 Android Auto 畫面提供個人化搜尋結果時。
  3. 保留:允許使用者將 Google 助理內顯示的小工具釘選到啟動器。釘選功能須使用小工具擴充功能程式庫

Google 助理如何顯示小工具

使用者可以透過兩種方式在 Google 助理叫用小工具:

  • 使用名稱明確要求使用小工具,或
  • 向 Google 助理以語音方式提出查詢,藉此觸發內建意圖 (BII) 或為小工具執行要求設定的自訂意圖

明確叫用

如果想為已經安裝的應用程式明確叫用小工具,使用者可以如此要求 Google 助理:

  • 「Ok Google,顯示範例應用程式的小工具」
  • 「範例應用程式的小工具。」

Google 助理會顯示這些小工具,並附上基本的簡介:「範例應用程式說:歡迎使用小工具」。雖然 Google 助理原本就可用此方法回傳要求的小工具,軟體開發人員無需額外進行操作,但是使用者必須要明確認識想要求的小工具,才能使用這個叫用方式。為了簡化小工具探索過程,請用下列章節詳細說明的意圖執行要求方法。

意圖執行要求

用您的小工具執行使用者透過 Google 助理提出的自然語言查詢內容,藉此讓使用者更容易找到小工具。舉例來說,您可以在使用者每次詢問「Ok Google,根據範例應用程式的數據,我這個禮拜跑了幾英里?」,因而在您的健身應用程式中觸發 GET_EXERCISE_OBSERVATION BII 時,回傳特定的小工具。整合小工具和應用程式動作除了可以簡化探索過程之外,還具有以下優點:

  • 參數存取權:Google 助理可以提供從使用者對小工具查詢內容中擷取的意圖參數,讓您得以提供量身訂作的回應
  • 自訂文字轉語音簡介:您可以在顯示小工具時,讓 Google 助理朗讀一段文字轉語音 (TTS) 字串。
  • 釘選小工具:Google 助理會在小工具附近顯示「新增這個小工具」按鈕,讓使用者可以輕鬆在啟動器中釘選小工具。

您必須在專案中加入小工具擴充功能程式庫才能使用自訂文字轉語音簡介和釘選小工具功能。

實作小工具

請按照以下步驟操作,以便實作小工具執行要求:

  1. 按照「建立簡易小工具」說明的步驟實作 Android 小工具。
  2. 在應用程式的 shortcuts.xml 資源檔案中,找到含有執行要求詳細資料及 BII <parameter> 標記的功能,然後新增 <app-widget> 元素。更新小工具,以便處理參數。
  3. (建議做法) 在您的 Android 專案中加入選用的小工具擴充功能程式庫,以便使用自訂文字轉語音簡介釘選小工具等功能。

以下章節將說明 shortcuts.xml<app-widget> 結構定義。

小工具結構定義

shortcuts.xml 內,<app-widget> 元素會定義為 <capability> 元素內的執行要求。除非註明為「非必要」,否則需要使用以下屬性:

Shortcuts.xml 標記包含於屬性
<app-widget> <capability>
  • android:identifier
  • android:targetClass
<parameter> <app-widget>
<extra> <app-widget>
  • android:name (僅適用於 TTS)
  • android:value (非必要)

小工具結構定義說明

<app-widget>

頂層小工具執行要求元素。

屬性:

  • android:identifier:此執行要求的專用 ID。此值應為專用值,不得與 <capability> 內定義的 <app-widget><intent> 執行要求元素重複。
  • android:targetClass:處理意圖的 AppWidgetProvider 的完整類別名稱。

<parameter>

將 BII 參數對應至意圖 <parameter> 值。您可以為每項 <app-widget> 元素定義 0 個以上的參數。執行要求時,Google 助理會更新小工具執行個體的額外功能,當做使用以下格式的鍵/值組合,藉此傳遞參數:

  • 鍵:參數定義的 android:key
  • 值:BII 從使用者語音輸入內容中擷取的值。

您會藉由在關聯的 AppWidgetManager 物件呼叫 getAppWidgetOptions(),並回傳含有觸發 BII 及參數名稱的 Bundle 存取這些額外功能。詳情請參閱「擷取參數值」。

如果想進一步瞭解 BII 參數比對,請見「參數資料和比對」。

<extra>

非必要標記,可用來宣告此小工具應該使用自訂文字轉語音簡介。這個標記須使用以下屬性值:

  • android:name:「hasTts」
  • android:value:「true」

程式碼範例

以下 XML 將展示 GET_EXERCISE_OBSERVATION BII 功能的小工具執行要求設定:

shortcuts.xml

<capability android:name="actions.intent.GET_EXERCISE_OBSERVATION">
  <app-widget
    android:identifier="GET_EXERCISE_OBSERVATION_1"
    android:targetClass="com.exampleapp.providers.exampleAppWidgetProvider"
    android:targetPackage="com.exampleapp">
    <parameter
      android:name="exerciseObservation.aboutExercise.name"
      android:key="exercisename">
    </parameter>
    <extra android:name="hasTts" android:value="true"/>
  </app-widget>
</capability>

每個功能都可以指定多個 <app-widget> 元素,或混合使用 <app-widget><intent> 元素。藉由此方法,您可以根據使用者提供的不同參數組合,提供自訂的使用體驗。舉例來說,如果使用者並未在查詢內容中指定下車地點,您可以指引使用者前往應用程式內顯示設定上車及下車地點的選項活動。定義備用意圖詳情請見「備用意圖」章節。

擷取參數值

在以下 AppWidgetProvider 類別範例中,系統使用不公開函式 updateAppWidget() 從小工具選項 Bundle 當中擷取 BII 名稱及參數:

Kotlin

package com.example.exampleapp

//... Other module imports
import com.google.assistant.appactions.widgets.AppActionsWidgetExtension

/**
 * Implementation of App Widget functionality.
 */
class MyAppWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        // There may be multiple widgets active, so update all of them
        for (appWidgetId in appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId)
        }
    }

    private fun updateAppWidget(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetId: Int
    ) {
        val widgetText: CharSequence = context.getString(R.string.appwidget_text)

        // Construct the RemoteViews object
        val views = RemoteViews(context.packageName, R.layout.my_app_widget)
        views.setTextViewText(R.id.appwidget_text, widgetText)

        // Extract the name and parameters of the BII from the widget options.
        val optionsBundle = appWidgetManager.getAppWidgetOptions(appWidgetId)
        val bii = optionsBundle.getString(AppActionsWidgetExtension.EXTRA_APP_ACTIONS_BII) // "actions.intent.CREATE_TAXI_RESERVATION"
        val params = optionsBundle.getBundle(AppActionsWidgetExtension.EXTRA_APP_ACTIONS_PARAMS)
        if (params != null && params.containsKey("dropoff")) {
            val dropoffLocation = params.getString("dropoff")
            // Build your RemoteViews with the extracted BII parameter
            // ...
        }
        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
}

Java

package com.example.exampleapp;

//... Other module imports
import com.google.assistant.appactions.widgets.AppActionsWidgetExtension;

/**
 * Implementation of App Widget functionality.
 */
public class MyAppWidget extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {

        CharSequence widgetText = context.getString(R.string.appwidget_text);

        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget);
        views.setTextViewText(R.id.appwidget_text, widgetText);

        // Extract the name and parameters of the BII from the widget options.
        Bundle optionsBundle = appWidgetManager.getAppWidgetOptions(appWidgetId);
        String bii =
                optionsBundle.getString(AppActionsWidgetExtension.EXTRA_APP_ACTIONS_BII); // "actions.intent.CREATE_TAXI_RESERVATION"
        Bundle params =
                optionsBundle.getBundle(AppActionsWidgetExtension.EXTRA_APP_ACTIONS_PARAMS);

        if (params != null && params.containsKey(("dropoff"))){
            String dropoffLocation = params.getString("dropoff");
            // Build your RemoteViews with the extracted BII parameter
            // ...
        }

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}

小工具擴充功能程式庫

應用程式動作小工具擴充功能程式庫可以加強小工具功能,提供以語音為主的 Google 助理使用體驗。這個 Maven 程式庫可以讓您為每個小工具提供自訂文字轉語音 (TTS) 簡介,讓 Google 助理朗讀轉譯內容的摘要。這個程式庫也能啟用啟動器釘選,讓使用者能夠輕鬆在啟動器畫面上儲存 Google 助理顯示的小工具。

先在應用程式模組 build.gradle 檔案的依附元件區段中加入此程式庫:

app/build.gradle

dependencies {
    //...
    implementation "com.google.assistant.appactions:widgets:0.0.1"
}

自訂簡介

匯入小工具擴充功能程式庫之後,您就能為小工具提供自訂文字轉語音簡介。若要將您的定義加入小工具的 AppWidgetProvider,請用 IDE 開啟類別,然後匯入小工具擴充功能程式庫:

Kotlin

import com.google.assistant.appactions.widgets.AppActionsWidgetExtension

Java

import com.google.assistant.appactions.widgets.AppActionsWidgetExtension;
接下來,請用程式庫定義您的簡介字串,然後更新小工具:
ExampleAppWidget

Kotlin

package com.example.exampleapp

//... Other module imports
import com.google.assistant.appactions.widgets.AppActionsWidgetExtension

/**
 * Implementation of App Widget functionality.
 */
object MyAppWidget : AppWidgetProvider() {
    fun updateAppWidget(
        context: Context?,
        appWidgetManager: AppWidgetManager,
        appWidgetId: Int
    ) {
        val appActionsWidgetExtension = AppActionsWidgetExtension.newBuilder(appWidgetManager)
            .setResponseSpeech("Hello world") // TTS to be played back to the user.
            .setResponseText("Hello world!") // Response text to be displayed in Assistant.
            .build()

        // Update widget with TTS.
        appActionsWidgetExtension.updateWidget(appWidgetId)

        // Update widget UI.
        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
}

Java

package com.example.exampleapp;

//... Other module imports
import com.google.assistant.appactions.widgets.AppActionsWidgetExtension;

/**
 * Implementation of App Widget functionality.
 */
public class MyAppWidget extends AppWidgetProvider {

  static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
    int appWidgetId) {

    AppActionsWidgetExtension appActionsWidgetExtension = AppActionsWidgetExtension.newBuilder(appWidgetManager)
      .setResponseSpeech("Hello world")  // TTS to be played back to the user.
      .setResponseText("Hello world!")  // Response text to be displayed in Assistant.
      .build();

      // Update widget with TTS.
      appActionsWidgetExtension.updateWidget(appWidgetId);

      // Update widget UI.
      appWidgetManager.updateAppWidget(appWidgetId, views);
    }

}

啟動器釘選

這個程式庫可讓系統在 Google 助理內的小工具旁邊顯示「新增這個小工具」按鈕。您必須將以下接收器定義加入 AndroidManifest.xml,才能使用釘選功能:

AndroidManifest.xml

<application>
  <receiver android:name="com.google.assistant.appactions.widgets.pinappwidget.PinAppWidgetBroadcastReceiver"
    android:exported="false">
    <intent-filter>
      <action android:name="com.google.assistant.appactions.widgets.COMPLETE_PIN_APP_WIDGET" />
    </intent-filter>
  </receiver>
  <service
    android:name=
    "com.google.assistant.appactions.widgets.pinappwidget.PinAppWidgetService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
      <action
        android:name="com.google.assistant.appactions.widgets.PIN_APP_WIDGET" />
    </intent-filter>
  </service>
</application>

清查可用情形

BII 支援內嵌清查網站清查也可以將這些清查擴充到小工具的執行要求。

內嵌清查

下列程式碼範例展示了為內嵌清查及小工具執行要求進行設定的 START_EXERCISE BII 功能:

shortcuts.xml

<capability
  android:name="actions.intent.START_EXERCISE">
  <app-widget
    android:identifier="START_EXERCISE_1"
    android:targetClass="com.example.exampleapp.StartExerciseAppWidgetProvider">
    <parameter
      android:name="exercise.name"
      android:key="exerciseName"
      app:shortcutMatchRequired="true">
    </parameter>
  </app-widget>
</capability>

<shortcut android:shortcutId="RunningShortcut">
  <intent
    android:action="android.intent.action.VIEW"
    android:targetClass="com.example.exampleapp.StartExcerciseActivity" />
  <capability-binding
    android:capability="actions.intent.START_EXERCISE"
    android:parameter="exercise.name"
    android:value="running;runs" />
</shortcut>

在上述範例中,當使用者要求 Google 助理「開始執行範例應用程式」並觸發此功能時,和 <app-widget> 執行要求組合的選項會含有以下的鍵/值組合:

  • 鍵 = “exerciseName”
  • 值 = “RunningShortcut”

網站清查

請看以下程式碼範例,瞭解網站清查及小工具執行要求啟用的功能:

shortcuts.xml

<shortcuts>
  <capability
    android:name="actions.intent.START_EXERCISE">
    <app-widget
      android:identifier="START_EXERCISE_1"
      android:targetClass="com.example.exampleapp.CreateTaxiAppWidgetProvider">
      <parameter
        android:name="exercise.name"
        android:key="exerciseName"
        android:mimeType="text/*">
        <data android:pathPattern="https://exampleapp.com/exercise/.*" />
      </parameter>
    </app-widget>
  </capability>
</shortcuts>

測試

應用程式動作測試工具是 Android Studio Google 助理外掛程式的其中一種功能,您可以用來在實體或虛擬裝置上測試小工具。如要使用這個測試工具,請按照下列步驟操作:

  1. 連結到執行您的應用程式的測試裝置。
  2. 在 Android Studio 中,前往「Tools」(工具) >「App Actions」(應用程式動作)>「App Actions Test Tool」(應用程式動作測試工具)
  3. 按一下「Create Preview」(建立預覽)
  4. 在 Android Studio 中,使用您的測試裝置執行應用程式。
  5. 在測試裝置上使用 Google 助理應用程式,藉此測試應用程式動作。例如,您可以說:「Ok Google,根據範例應用程式的數據,我這個禮拜跑了幾英里?」
  6. 觀察應用程式行為,或使用 Android Studio 偵錯工具確認是否達到想要的動作結果。

品質指南

本節特別說明整合應用程式動作與小工具時的重要必要條件和最佳做法。

小工具內容

  • (必要條件) 您不得在小工具中顯示廣告。
  • 小工具內容應該完全注重於如何執行議題,請勿嘗試用單一小工具執行多種意圖,或加入不相關的內容。

處理驗證

  • (必要條件) 如果使用者必須通過驗證才能完成使用者流程,請回傳說明的小工具,解釋使用者需要到應用程式繼續操作。應用程式動作不支援透過 Google 助理提供內嵌使用者驗證。
  • 如果使用者允許您的應用程式使用小工具顯示資料,則您可以在執行階段回傳錯誤小工具,說明有未經授權的使用者。

備用意圖

  • (必要條件) 在 shortcuts.xml 中,每個功能皆需在小工具執行要求之外提供備用的 <intent>。備用意圖是 <intent> 元素,不需使用 <parameter> 值。這樣可讓 Google 助理在使用者查詢內容內並無功能內定義的其他執行要求元素所需的參數時,依然可以執行動作。當該功能並無所需的參數時,則不在此限,這種情況只需要小工具執行要求。
  • 備用意圖應該開啟您的應用程式,並進入相關的應用程式畫面,而不是主畫面。

以下程式碼會展示設有支援主要 <app-widget> 執行要求的備用 <intent><capability>

shortcuts.xml

<shortcuts>
  <capability
    android:name="actions.intent.CREATE_TAXI_RESERVATION">
    <!-- Widget with required parameter, specified using the "android:required" attribute. -->
    <app-widget
      android:identifier="CREATE_TAXI_RESERVATION_1"
      android:targetClass="com.example.myapplication.CreateTaxiAppWidgetProvider">
      <parameter
        android:name="taxiReservation.dropoffLocation.name"
        android:key="dropoff"
        android:required="true">
      </parameter>
    </app-widget>
    <!-- Fallback intent with no parameters required to successfully execute. -->
    <intent
      android:identifier="CREATE_TAXI_RESERVATION_3"
      android:action="myapplication.intent.CREATE_TAXI_RESERVATION_1"
      android:targetClass="com.example.myapplication.TaxiReservationActivity">
    </intent>
  </capability>
</shortcuts>

Google Play 資料揭露

本章節會列出最新版小工具擴充功能程式庫會收集的使用者資料。

此 SDK 會傳送由開發人員提供的文字轉語音 (TTS) 回應,Google 助理會使用助理語音技術為使用者朗讀這段回應。Google 不會儲存這項資訊。

應用程式動作也可能會為了以下目的而收集用戶端應用程式的中繼資料:

  • 監控不同 SDK 版本的採用率。
  • 量化分析各應用程式之間的 SDK 功能使用情形。