AppFunctions API in Ihre App einbinden

In diesem Leitfaden wird erläutert, wie Sie die AppFunctions API in Ihre Android-App einbinden, die Logik für eine Funktion implementieren und überprüfen, ob die Integration ordnungsgemäß funktioniert.

Versionskompatibilität

Für diese Implementierung muss compileSdk Ihres Projekts auf API-Level 36 oder höher festgelegt sein.

Ihre App muss nicht prüfen, ob AppFunctions unterstützt werden. Das wird automatisch in der AppFunctions Jetpack-Bibliothek erledigt. AppFunctionManager gibt eine Instanz zurück, wenn das Feature unterstützt wird, andernfalls wird „null“ zurückgegeben.

Abhängigkeiten

Fügen Sie die erforderlichen Bibliotheksabhängigkeiten der Datei build.gradle.kts (oder build.gradle) Ihres Moduls hinzu und konfigurieren Sie das KSP-Plug-in in Ihrem App-Modul auf oberster Ebene wie unten dargestellt:

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-Logik implementieren

Wenn Sie eine AppFunction für Ihre Android-App implementieren möchten, erstellen Sie eine Klasse, die die spezifische AppFunctions-Logik implementiert. Dazu müssen serialisierbare Datenklassen für Parameter und Antworten erstellt und dann die Kernlogik in der Funktionsmethode bereitgestellt werden.

Der folgende Code zeigt eine Beispielimplementierung zum Erstellen einer Aufgabe in der TODO-App, einschließlich der Definition benutzerdefinierter Parameter und Antworttypen sowie der Hauptfunktionslogik mit einem Repository.

@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.
     */
    @AppFunction(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)
}

Wichtige Punkte zum Code

  • Standardmäßig wird eine AppFunction-Implementierung im Android-UI-Thread ausgeführt. Ein Vorgang mit langer Ausführungszeit sollte daher Folgendes tun:
    • Deklarieren Sie die AppFunction als suspend-Funktion.
    • Wechseln Sie zu einem geeigneten Coroutine-Dispatcher, wenn der Vorgang den Thread blockieren könnte.
  • Wenn isDescribedByKDoc auf true festgelegt ist, wird die Funktionsbeschreibung oder die serialisierbare Beschreibung als Teil von AppFunctionMetadata codiert, damit der Agent versteht, wie die AppFunction der App verwendet werden soll.

AppFunction-Dienst im Manifest deklarieren

Registrieren Sie die KSP-generierte Dienstdeklaration und die app_metadata-Property in Ihrem Modulmanifest, z. B. in src/main/AndroidManifest.xml. Der KSP-Compiler generiert die konkrete Dienstklasse (TaskAppFunctionService), die Ihre abstrakte Einstiegspunktklasse erweitert, sowie das entsprechende XML-Schema in Ihrem assets/-Verzeichnis.

<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" />

Optional: AppFunction-Verfügbarkeit zur Laufzeit umschalten

Verwenden Sie die AppFunctionManager API, um Funktionen explizit zu aktivieren oder zu deaktivieren, wenn Sie Ihre AppFunctions einschränken. Gating kann nützlich sein, wenn bestimmte Funktionen Ihrer App nicht für alle Nutzer verfügbar sind. Durch das dynamische Aktivieren oder Deaktivieren von AppFunctions weiß das KI-System genau, welche Funktionen für Ihren Nutzer zu einem bestimmten Zeitpunkt verfügbar sind.

Wenn Sie AppFunctions, für die ein bestimmter Kontostatus erforderlich ist, sicher einschränken möchten, gehen Sie in zwei Schritten vor:

Schritt 1: Funktion standardmäßig deaktivieren

Damit die Funktion nicht zugänglich ist, bevor Ihr Funktions-Flag überprüft wurde, setzen Sie den Parameter isEnabled Ihrer @AppFunction-Annotation auf false.

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

Schritt 2: Funktion dynamisch zur Laufzeit aktivieren

Für jede AppFunction-Klasse generiert der Compiler eine entsprechende Klasse mit Funktions-ID-Konstanten (mit dem Suffix Ids). Sie können diese generierten ID-Konstanten zusammen mit der Methode setAppFunctionEnabled aus AppFunctionManagerCompat verwenden, um den aktivierten Status einer Funktion zur Laufzeit zu ändern.

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

Überlegungen zu den Arten von Funktionen, die zur Verfügung gestellt werden sollen

Sicherheit hat immer oberste Priorität. Wenn Sie auswählen, welche Funktionen Ihrer App als AppFunctions verfügbar gemacht werden sollen, sollten Sie bedenken, dass System-Agents Nutzeranfragen auf dem Server verarbeiten können, um erweiterte LLM-Funktionen zu nutzen.

Damit Nutzer eine positive Erfahrung machen und gleichzeitig keine vertraulichen Informationen preisgegeben werden, empfehlen wir Ihnen, die folgenden Richtlinien zu beachten:

  • Funktionen, die von natürlicher Sprache profitieren: Stellen Sie Aufgaben zur Verfügung, die ein Nutzer leichter in einem Gespräch als durch manuelle UI-Navigation ausdrücken kann.
  • Eingeschränkter Zugriff: Erstellen Sie AppFunctions, die dem Agent nur Zugriff auf Daten und Aktionen gewähren, die zur Erfüllung der spezifischen Anfrage des Nutzers erforderlich sind.
  • Nicht vertrauliche Informationen: Geben Sie nur Daten weiter, die nicht hochgradig persönlich oder vertraulich sind, oder Daten, deren Weitergabe der Nutzer im Kontext der Aktion ausdrücklich zustimmt.
  • Eindeutige Bestätigung für alle destruktiven Aktionen: Seien Sie äußerst vorsichtig bei Funktionen, die destruktive Aktionen ausführen (z. B. das Löschen von Daten). Auch wenn der KI-Agent sie aufrufen kann, sollte Ihre App einen eigenen Bestätigungsschritt enthalten und eine klare, eindeutige Sprache verwenden, um die Absichten zu beschreiben. Es ist auch hilfreich, mehr als einen Bestätigungsschritt hinzuzufügen, um wirklich sicherzustellen, dass der Nutzer weiß, was er tun soll.

AppFunction-Integration prüfen

Mit adb shell cmd app_function können Sie prüfen, ob Sie AppFunctions richtig integriert haben.

Verwenden Sie adb shell cmd app_function list-app-functions | grep --after-context 10 $myPackageName, um Details zu den AppFunctions Ihrer App aufzurufen.

Sie können eine AppFunction auch direkt über die Befehlszeile mit ihrer expliziten ID ("$enclosingClassName#$methodName") ausführen:

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\"}}'"

Wenn Sie Android MCP in Aktion sehen und End-to-End-Workflows ohne Aufforderungen überprüfen möchten, installieren Sie die Android-App AppFunctions testing agent auf Ihrem Gerät und führen Sie sie aus.

Wenn Sie Ihre Integration mit chatbasierten Assistenten wie Gemini in Android Studio überprüfen, verwenden Sie die Entwickler-Skill „AppFunctions“ oder geben Sie einen Prompt wie den folgenden ein:

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.

Von niedrigeren API-Versionen migrieren

In Version 1.0.0-alpha10 wurde in AppFunctions eine @AppFunctionServiceEntryPoint-Architektur für die Kompilierzeit eingeführt, die Bibliotheksabhängigkeiten konsolidiert und Legacy-Konfigurationsanbieter (AppFunctionConfiguration.Provider) ersetzt.

Wenn Ihre App derzeit eine frühere Version von AppFunctions verwendet (z. B. 1.0.0-alpha09), können Sie die Migration mit dem AppFunctions-Agent-Skill in einer KI-IDE wie Gemini in Android Studio automatisieren. Der Skill enthält spezielle Migrationsregeln, die einen Agenten anleiten, Ihre Build-Abhängigkeiten zu konsolidieren, den erforderlichen @AppFunctionServiceEntryPoint-Service-Wrapper zu erstellen, Kontextparameter zu entkoppeln und Ihre Manifestdeklarationen zu aktualisieren.

Um eine automatisierte Migration mit Ihrem KI-Agenten zu starten, verwenden Sie einen Prompt wie den folgenden:

Use the AppFunctions migration skill to upgrade my app's AppFunctions implementation from 1.0.0-alpha09 to the 1.0.0-alpha10 @AppFunctionServiceEntryPoint architecture.