在應用程式中加入 AppFunctions API

本指南說明如何將 AppFunctions API 整合至 Android 應用程式、實作函式邏輯,以及驗證整合是否正確運作。

版本相容性

這項實作要求專案 compileSdk 必須設為 API 級別 36 以上。

應用程式不需要驗證是否支援 AppFunctions,AppFunctions Jetpack 程式庫會自動處理這項作業。如果支援該功能,AppFunctionManager 會傳回例項,否則會傳回空值。

依附元件

將必要的程式庫依附元件新增至模組的 build.gradle.kts (或 build.gradle) 檔案,並在頂層應用程式模組中設定 KSP 外掛程式,如下所示:

dependencies {
  implementation("androidx.appfunctions:appfunctions:1.0.0-alpha10")
  // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP)
  // See Add the KSP plugin to your project
  ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha10")
}

實作 AppFunctions 邏輯

如要為 Android 應用程式實作 AppFunction,請建立一個類別,用於實作特定的 AppFunctions 邏輯。這包括為參數和回應建立可序列化的資料類別,然後在函式方法中提供核心邏輯。

下列程式碼範例說明如何在 TODO 應用程式中建立工作,包括定義自訂參數和回應類型,以及使用存放區定義主要函式邏輯。

@RequiresApi(36)
@AndroidEntryPoint
@AppFunctionServiceEntryPoint(
    serviceName = "TaskAppFunctionService",
    appFunctionXmlFileName = "task_app_function_service",
)
abstract class BaseTaskAppFunctionService : AppFunctionService() {
    @Inject internal lateinit var taskRepository: TaskRepository

    /**
     * Creates a task based on [createTaskParams].
     *
     * @param createTaskParams The parameter to describe how to create the task.
     */
    @AppFunctionDeclaration(isDescribedByKDoc = true)
    suspend fun createTask(
        createTaskParams: CreateTaskParams,
    ): Task = withContext(Dispatchers.IO) {
        // Developers can use predefined exceptions to let the agent know
        // why it failed.
        if (createTaskParams.title == null && createTaskParams.content == null) {
            throw AppFunctionInvalidArgumentException("Title or content should be non-null")
        }

        val id = taskRepository.createTask(
            createTaskParams.title,
            createTaskParams.content
        )

        return@withContext taskRepository
            .getTask(id)
            ?.toTask()
            ?: throw AppFunctionElementNotFoundException("Task not found for ID = $id")
    }

    // Maps internal TaskEntity
    private fun TaskEntity.toTask() = Task(id = id, title = title, content = description)
}

程式碼重點

  • 根據預設,AppFunction 實作會在 Android UI 執行緒中執行。因此,長時間執行的作業應執行下列操作:
    • 將 AppFunction 宣告為暫停函式。
    • 當作業可能封鎖執行緒時,請切換至合適的協同程式調度工具。
  • 如果 isDescribedByKDoc 設為 true,函式說明或可序列化說明會編碼為 AppFunctionMetadata 的一部分,協助代理程式瞭解如何使用應用程式的 AppFunction。

在資訊清單中宣告 AppFunction 服務

在模組資訊清單 (例如 src/main/AndroidManifest.xml) 中,註冊 KSP 產生的服務宣告和 app_metadata 屬性。 KSP 編譯器會產生具體服務類別 (TaskAppFunctionService) ,擴充抽象進入點類別,並在 assets/ 目錄中產生對應的 XML 架構。

<service
    android:name="com.example.snippets.ai.TaskAppFunctionService"
    android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
    android:exported="true"
    tools:targetApi="36">
    <property
        android:name="android.app.appfunctions.schema"
        android:value="app_functions_schema.xsd" />
    <property
        android:name="android.app.appfunctions.v2"
        android:value="task_app_function_service.xml" />
    <intent-filter>
        <action android:name="android.app.appfunctions.AppFunctionService" />
    </intent-filter>
</service>
<property
    android:name="android.app.appfunctions.app_metadata"
    android:resource="@xml/app_metadata" />

選用:在執行階段切換 AppFunction 可用性

在限制 AppFunctions 時,請使用 AppFunctionManager API 明確啟用或停用函式。如果應用程式的某些功能不適用於所有使用者,則可使用閘控功能。動態啟用或停用 AppFunctions,可讓智慧系統確切知道使用者在任何特定時間可使用哪些功能。

如要安全地限制需要特定帳戶狀態的 AppFunction,請按照下列兩個步驟操作:

步驟 1:預設停用函式

為避免在功能旗標驗證前存取函式,請將 @AppFunction 註解的 isEnabled 參數設為 false。

@AppFunctionDeclaration(isEnabled = false, isDescribedByKDoc = true)
suspend fun createTask(
    createTaskParams: CreateTaskParams,
): Task = TODO()

步驟 2:在執行階段動態啟用函式

對於每個 AppFunction 類別,編譯器會產生包含函式 ID 常數的對應類別 (使用 Ids 後置字元)。您可以將這些產生的 ID 常數與 AppFunctionManagerCompat 的 setAppFunctionEnabled 方法搭配使用,在執行階段變更函式的啟用狀態。

suspend fun onFeatureEnabled(context: Context) {
    try {
        AppFunctionManager.getInstance(context)
            ?.setAppFunctionEnabled(
                BaseTaskAppFunctionServiceIds.CREATE_TASK_ID,
                AppFunctionManager.APP_FUNCTION_STATE_ENABLED,
            )
    } catch (e: Exception) {
        // Handle exception: AppFunctions indexation may not be fully completed
        // upon initial app startup.
    }
}

suspend fun onFeatureDisabled(context: Context) {
    try {
        AppFunctionManager.getInstance(context)
            ?.setAppFunctionEnabled(
                BaseTaskAppFunctionServiceIds.CREATE_TASK_ID,
                AppFunctionManager.APP_FUNCTION_STATE_DISABLED,
            )
    } catch (e: Exception) {
        // Handle exception
    }
}

提供功能類型時的考量

安全性一向是首要考量。選擇要將應用程式的哪些功能設為 AppFunction 時,請務必注意,系統代理程式可能會在伺服器上處理使用者查詢,以便運用進階 LLM 功能。

為提供優質的使用者體驗,同時避免洩漏私密資訊,建議您遵循下列規範:

  • 適合使用自然語言的功能:提供使用者更容易透過對話表達,而非手動操作 UI 的工作。
  • 縮小存取範圍:建立 AppFunction,只授予代理程式執行使用者特定要求所需的資料和動作存取權。
  • 非機密資訊:僅分享非高度個人或機密的資料,或使用者在動作情境中明確同意分享的資料。
  • 任何破壞性動作都必須明確確認:執行破壞性動作 (例如刪除資料) 的函式必須格外謹慎。雖然代理可能會叫用這些動作,但應用程式應包含自己的確認步驟,並使用清楚明確的語言說明意圖。此外,建議您加入多個確認步驟,確保使用者確實瞭解系統要求他們執行的操作。

驗證 AppFunction 整合

如要確認是否已正確整合 AppFunctions,可以使用 adb shell cmd app_function。

使用 adb shell cmd app_function list-app-functions | grep --after-context 10 $myPackageName 查看應用程式提供的 AppFunctions 詳細資料。

您也可以使用明確 ID ("$enclosingClassName#$methodName"),直接從指令列執行 AppFunction:

adb shell "cmd app_function execute-app-function \
  --package com.example.android.appfunctions \
  --function 'com.example.android.appfunctions.BaseTaskAppFunctionService#createTask' \
  --parameters '{\"createTaskParams\": {\"title\": \"Buy milk\", \"content\": \"From grocery store\"}}'"

如要體驗 Android MCP 的實際運作情形,並驗證端對端工作流程,而不需任何提示,請在裝置上安裝並執行 AppFunctions 測試代理程式 Android 應用程式。

如果您使用 Android Studio 中的 Gemini 等對話式助理驗證整合,請使用 AppFunctions 開發技能,或提供類似以下的提示:

Execute `adb shell cmd app_function` to learn how the tool works, then act as a
chat agent aiming to invoke AppFunctions to fulfil user prompts for this app.
Rely on the AppFunction description as instructions.

從較低 API 版本遷移

在 1.0.0-alpha10 版中,AppFunctions 導入了編譯時間 @AppFunctionServiceEntryPoint 架構,可整合程式庫依附元件,並取代舊版設定供應器 (AppFunctionConfiguration.Provider)。

如果應用程式目前使用舊版 AppFunctions (例如 1.0.0-alpha09),您可以在 AI IDE (例如 Android Studio 內建 Gemini) 中,使用 AppFunctions 代理程式技能自動遷移。這項技能包含專屬遷移規則,可引導代理整合建構依附元件、建立必要的 @AppFunctionServiceEntryPoint 服務包裝函式、分離情境參數,以及更新資訊清單宣告。