Questa guida spiega come integrare l'API AppFunctions nella tua app per Android, implementare la logica per una funzione e verificare che l'integrazione funzioni correttamente.
Compatibilità delle versioni
Questa implementazione richiede che compileSdk del progetto sia impostato sul livello API 36 o superiore.
Non è necessario che la tua app verifichi se AppFunctions è supportato. Questa operazione viene gestita automaticamente all'interno della libreria Jetpack AppFunctions.
AppFunctionManager restituisce un'istanza se la funzionalità è supportata e restituisce null in caso contrario.
Dipendenze
Aggiungi le dipendenze della libreria richieste al file build.gradle.kts (o build.gradle) del modulo e configura il plug-in KSP nel modulo dell'app di primo livello come mostrato di seguito:
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")
}
Implementare la logica di AppFunctions
Per implementare un'AppFunction per la tua app per Android, crea una classe che implementi la logica specifica di AppFunctions. Ciò comporta la creazione di classi di dati serializzabili per parametri e risposte, quindi la fornitura della logica principale all'interno del metodo della funzione.
Il seguente codice mostra un'implementazione di esempio per la creazione di un'attività nell' app TODO, inclusa la definizione di parametri e tipi di risposta personalizzati e la logica della funzione principale utilizzando un 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) }
Punti chiave sul codice
- Per impostazione predefinita, un'implementazione di AppFunction viene eseguita nel thread dell'interfaccia utente di Android.
Pertanto, un'operazione a lunga esecuzione deve:
- Dichiarare AppFunction come funzione di sospensione.
- Passare a un dispatcher di coroutine appropriato quando l'operazione potrebbe bloccare il thread.
- Quando
isDescribedByKDocè impostato sutrue, la descrizione della funzione o la descrizione serializzabile viene codificata come parte diAppFunctionMetadataper aiutare l'agente a capire come utilizzare AppFunction dell'app.
Dichiarare il servizio AppFunction nel file manifest
Registra la dichiarazione del servizio generata da KSP e la proprietà app_metadata all'interno del file manifest del modulo, ad esempio in src/main/AndroidManifest.xml. Il compilatore KSP genera la classe di servizio concreta (TaskAppFunctionService) che estende la classe del punto di ingresso astratto, insieme allo schema XML corrispondente nella directory assets/.
<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" />
(Facoltativo) Attivare/disattivare la disponibilità di AppFunction in fase di runtime
Utilizza l'API AppFunctionManager per attivare o disattivare esplicitamente le funzioni quando limiti le AppFunctions. La limitazione può essere utile quando alcune funzionalità dell'app non sono disponibili per tutti gli utenti. Abilitando o disabilitando dinamicamente le AppFunctions, il sistema di intelligence sa esattamente quali funzionalità sono disponibili per l'utente in un determinato momento.
Per limitare in modo sicuro le AppFunctions che richiedono uno stato dell'account specifico, segui una procedura in due passaggi:
Passaggio 1. Disattivare la funzione per impostazione predefinita
Per impedire l'accesso alla funzione prima della verifica del flag di funzionalità, imposta il parametro isEnabled dell'annotazione @AppFunction su false.
@AppFunction(isEnabled = false, isDescribedByKDoc = true) suspend fun createTask( createTaskParams: CreateTaskParams, ): Task = TODO()
Passaggio 2. Attivare dinamicamente la funzione in fase di runtime
Per ogni classe AppFunction, il compilatore genera una classe corrispondente contenente costanti ID funzione (utilizzando un suffisso Ids). Puoi utilizzare queste costanti ID generate insieme al metodo setAppFunctionEnabled di AppFunctionManagerCompat per modificare lo stato di attivazione di una funzione in fase di runtime.
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 } }
Considerazioni sui tipi di funzionalità da rendere disponibili
La sicurezza è sempre fondamentale. Quando scegli le funzionalità della tua app da rendere disponibili come AppFunctions, è importante ricordare che gli agenti di sistema potrebbero elaborare le query degli utenti sul server per sfruttare le funzionalità avanzate dei modelli linguistici di grandi dimensioni.
Per offrire un'esperienza utente ottimale ed evitare di esporre informazioni sensibili, ti consigliamo di seguire queste linee guida:
- Funzionalità che sfruttano il linguaggio naturale: rendi disponibili le attività che un utente può esprimere più facilmente in una conversazione che tramite la navigazione manuale dell'interfaccia utente.
- Accesso limitato: crea AppFunctions che consentano all'agente di accedere solo ai dati e alle azioni necessari per soddisfare la richiesta specifica dell'utente.
- Informazioni non sensibili: condividi solo dati che non siano altamente personali o riservati oppure dati che l'utente acconsente esplicitamente a condividere nel contesto dell'azione.
- Conferma non ambigua per qualsiasi azione distruttiva: presta estrema attenzione alle funzioni che eseguono azioni distruttive (ad esempio l'eliminazione dei dati). Sebbene l'agente possa richiamarle, la tua app deve includere il proprio passaggio di conferma e utilizzare un linguaggio chiaro e non ambiguo sulle intenzioni. È anche utile aggiungere più di un passaggio di conferma per assicurarsi che l'utente sia consapevole di ciò che gli viene chiesto di fare.
Verificare l'integrazione di AppFunction
Per verificare se hai integrato correttamente AppFunctions, puoi utilizzare adb
shell cmd app_function.
Utilizza adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName per visualizzare i dettagli delle AppFunctions fornite dalla tua app.
Puoi anche eseguire un'AppFunction direttamente dalla riga di comando utilizzando il suo
identificatore esplicito ("$enclosingClassName#$methodName"):
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\"}}'"
Per provare Android MCP in azione e verificare i workflow end-to-end senza bisogno di prompt, installa ed esegui l'app per Android dell'agente di test AppFunctions agent sul tuo dispositivo.
Se stai verificando l'integrazione utilizzando assistenti basati sulla chat come Gemini in Android Studio, utilizza la skill di sviluppo AppFunctions o fornisci un prompt come il seguente:
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.
Eseguire la migrazione da versioni API precedenti
Nella versione 1.0.0-alpha10, AppFunctions ha introdotto un'architettura @AppFunctionServiceEntryPoint in fase di compilazione che consolida le dipendenze della libreria e sostituisce i provider di configurazione legacy (AppFunctionConfiguration.Provider).
Se la tua app utilizza una versione precedente di AppFunctions (ad esempio
1.0.0-alpha09), puoi automatizzare la migrazione utilizzando la skill
dell'agente AppFunctions in un IDE AI come Gemini in Android Studio. La skill contiene regole di migrazione dedicate che guidano un agente a consolidare le dipendenze della build, creare il wrapper del servizio @AppFunctionServiceEntryPoint richiesto, disaccoppiare i parametri di contesto e aggiornare le dichiarazioni del file manifest.
Skill per Android
Visualizza su GitHubImplementare AppFunctions
android skills add --skill appfunctionsUse the AppFunctions migration skill to upgrade my app's AppFunctions implementation from 1.0.0-alpha09 to the 1.0.0-alpha10 @AppFunctionServiceEntryPoint architecture.