En esta guía, se explica cómo integrar la API de AppFunctions en tu app para Android, implementar la lógica de una función y verificar que la integración funcione correctamente.
Compatibilidad de versiones
Esta implementación requiere que tu proyecto compileSdk se establezca en el nivel de API 36 o superior.
No es necesario que tu app verifique si se admiten AppFunctions. Esto se controla automáticamente dentro de la biblioteca de AppFunctions Jetpack.
AppFunctionManager muestra una instancia si se admite la función y muestra un valor nulo si no se admite.
Dependencias
Agrega las dependencias de biblioteca necesarias al archivo build.gradle.kts (o build.gradle) de tu módulo y configura el complemento de KSP en el módulo de la app de nivel superior como se muestra a continuación:
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")
}
Implementa la lógica de AppFunctions
Para implementar una AppFunction en tu app para Android, crea una clase que implemente la lógica específica de AppFunctions. Esto implica crear clases de datos serializables para parámetros y respuestas, y luego proporcionar la lógica principal dentro del método de función.
En el siguiente código, se muestra un ejemplo de implementación para crear una tarea en la app de tareas pendientes, incluida la definición de parámetros personalizados y tipos de respuesta y la lógica de la función principal con un repositorio.
@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) }
Puntos clave sobre el código
- De forma predeterminada, una implementación de AppFunction se ejecuta en el subproceso de IU de Android.
Por lo tanto, una operación de larga duración debe hacer lo siguiente:
- Declarar la AppFunction como una función de suspensión
- Cambiar a un dispatcher de corrutina adecuado cuando la operación pueda bloquear el subproceso
- Cuando
isDescribedByKDocse establece entrue, la descripción de la función o la descripción serializable se codifica como parte deAppFunctionMetadatapara ayudar al agente a comprender cómo usar la AppFunction de la app.
Declara el servicio de AppFunction en tu manifiesto
Registra la declaración de servicio generada por KSP y la propiedad app_metadata dentro del manifiesto de tu módulo, por ejemplo, en src/main/AndroidManifest.xml. El compilador de KSP genera la clase de servicio concreta (TaskAppFunctionService) que extiende tu clase de punto de entrada abstracto, junto con el esquema XML correspondiente en tu directorio 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" />
Opcional: Activa o desactiva la disponibilidad de AppFunction en el tiempo de ejecución
Usa la API de AppFunctionManager para habilitar o inhabilitar funciones de forma explícita cuando limites tus AppFunctions. La limitación puede ser útil cuando ciertas funciones de tu app no están disponibles para todos los usuarios. Si habilitas o inhabilitas AppFunctions de forma dinámica, el sistema de inteligencia sabe exactamente qué funciones están disponibles para tu usuario en un momento determinado.
Para limitar de forma segura las AppFunctions que requieren un estado de cuenta específico, sigue un proceso de dos pasos:
Paso 1: Inhabilita la función de forma predeterminada
Para evitar que se pueda acceder a la función antes de que se verifique tu marca de función, establece el parámetro isEnabled de tu anotación @AppFunction en false.
@AppFunction(isEnabled = false, isDescribedByKDoc = true) suspend fun createTask( createTaskParams: CreateTaskParams, ): Task = TODO()
Paso 2: Habilita la función de forma dinámica en el tiempo de ejecución
Para cada clase AppFunction, el compilador genera una clase correspondiente que contiene constantes de ID de función (con un sufijo Ids). Puedes usar estas constantes de ID generadas junto con el método setAppFunctionEnabled de AppFunctionManagerCompat para cambiar el estado habilitado de una función en el tiempo de ejecución.
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 } }
Consideraciones sobre los tipos de funcionalidades que se deben poner a disposición
La seguridad es siempre prioritaria. Cuando elijas qué capacidades de tu app poner a disposición como AppFunctions, es importante recordar que los agentes del sistema pueden procesar las consultas de los usuarios en el servidor para aprovechar las capacidades avanzadas de LLM.
Para proporcionar una excelente experiencia del usuario que también evite exponer información sensible, te recomendamos que sigas estas instrucciones:
- Funcionalidad que se beneficia del lenguaje natural: Pon a disposición tareas que sean más fáciles de expresar para un usuario en una conversación que a través de la navegación manual por la IU.
- Acceso limitado: Crea AppFunctions que solo le den al agente acceso a los datos y las acciones que se requieren para cumplir con la solicitud específica del usuario.
- Información no sensible: Solo comparte datos que no sean altamente personales o confidenciales, o datos que el usuario acepte compartir de forma explícita en el contexto de la acción.
- Confirmación inequívoca para cualquier acción destructiva: Ten mucho cuidado con las funciones que realizan acciones destructivas (como borrar datos). Si bien el agente puede invocarlas, tu app debe incluir su propio paso de confirmación y usar un lenguaje claro e inequívoco sobre las intenciones. También es útil agregar más de un paso de confirmación para garantizar que el usuario sepa lo que se le pide que haga.
Verifica la integración de AppFunction
Para verificar si integraste correctamente AppFunctions, puedes usar adb
shell cmd app_function.
Usa adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName para ver los detalles de las AppFunctions que proporciona tu app.
También puedes ejecutar una AppFunction directamente desde la línea de comandos con su
identificador explícito ("$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\"}}'"
Para experimentar Android MCP en acción y verificar los flujos de trabajo de extremo a extremo sin necesidad de instrucciones, instala y ejecuta la app para Android del agente de pruebas de AppFunctions en tu dispositivo.
Si verificas tu integración con asistentes basados en chat como Gemini en Android Studio, usa la habilidad de desarrollo de AppFunctions o proporciona una instrucción como la siguiente:
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.
Migra desde versiones de API inferiores
En la versión 1.0.0-alpha10, AppFunctions introdujo una arquitectura @AppFunctionServiceEntryPoint en tiempo de compilación que consolida las dependencias de la biblioteca y reemplaza los proveedores de configuración heredados (AppFunctionConfiguration.Provider).
Si tu app usa actualmente una versión anterior de AppFunctions (como
1.0.0-alpha09), puedes automatizar la migración con la habilidad del agente de AppFunctions en un IDE de IA como Gemini en Android Studio. La habilidad contiene reglas de migración dedicadas que guían a un agente para consolidar tus dependencias de compilación, crear el wrapper de servicio @AppFunctionServiceEntryPoint requerido, desacoplar los parámetros de contexto y actualizar las declaraciones de manifiesto.
Habilidades de Android
Ver en GitHubImplementa 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.