Este guia explica como integrar a API AppFunctions ao seu app Android, implementar a lógica de uma função e verificar se a integração funciona corretamente.
Compatibilidade de versões
Essa implementação exige que o compileSdk do projeto seja definido como o nível 36 da API
ou mais recente.
O app não precisa verificar se as AppFunctions são compatíveis. Isso é
processado automaticamente na biblioteca AppFunctions do Jetpack.
AppFunctionManager vai retornar uma instância se o recurso for compatível e
nulo se não for.
Dependências
Adicione as dependências de biblioteca necessárias ao arquivo build.gradle.kts (ou
build.gradle) do módulo e configure o plug-in do KSP no módulo do app de nível superior, como
mostrado abaixo:
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")
}
Implementar a lógica do AppFunctions
Para implementar uma AppFunction no seu app Android, crie uma classe que implemente a lógica específica das AppFunctions. Isso envolve a criação de classes de dados serializáveis para parâmetros e respostas e, em seguida, o fornecimento da lógica principal no método da função.
O código a seguir mostra um exemplo de implementação para criar uma tarefa no app TODO, incluindo a definição de parâmetros personalizados e tipos de resposta, além da lógica da função principal usando um repositório.
@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) }
Pontos principais sobre o código
- Por padrão, uma implementação de AppFunction é executada na linha de execução de interface do Android.
Portanto, uma operação de longa duração precisa fazer o seguinte:
- Declare a AppFunction como uma função de suspensão.
- Mude para um agente de corrotina adequado quando a operação puder bloquear a linha de execução.
- Quando
isDescribedByKDocé definido comotrue, a descrição da função ou a descrição serializável é codificada como parte doAppFunctionMetadatapara ajudar o agente a entender como usar a AppFunction do app.
Declarar o serviço AppFunction no manifesto
Registre a declaração de serviço gerada pelo KSP e a propriedade app_metadata
no manifesto do módulo, por exemplo, em src/main/AndroidManifest.xml. O
compilador do KSP gera a classe de serviço concreta (TaskAppFunctionService)
que estende a classe de ponto de entrada abstrata, além do esquema XML
correspondente no diretório 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: alternar a disponibilidade da AppFunction no momento da execução
Use a API AppFunctionManager para ativar ou desativar explicitamente as funções ao
restringir as AppFunctions. A restrição pode ser útil quando determinados recursos do app
não estão disponíveis para todos os usuários. Ao ativar ou desativar dinamicamente as
AppFunctions, o sistema de inteligência sabe exatamente quais recursos estão disponíveis
para o usuário em um determinado momento.
Para restringir com segurança as AppFunctions que exigem um estado de conta específico, siga um processo de duas etapas:
Etapa 1. Desativar a função por padrão
Para evitar que a função seja acessada antes que a flag de recurso seja
verificada, defina o parâmetro isEnabled da anotação @AppFunction como
false.
@AppFunction(isEnabled = false, isDescribedByKDoc = true) suspend fun createTask( createTaskParams: CreateTaskParams, ): Task = TODO()
Etapa 2: Ativar a função dinamicamente no ambiente de execução
Para cada classe AppFunction, o compilador gera uma classe correspondente
que contém constantes de ID de função (usando um sufixo Ids). É possível usar essas
constantes de ID geradas com o método setAppFunctionEnabled de
AppFunctionManagerCompat para mudar o estado ativado de uma função no momento da execução.
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 } }
Considerações sobre os tipos de funcionalidades a serem disponibilizadas
A segurança é sempre fundamental. Ao escolher quais recursos do seu app serão disponibilizados como AppFunctions, é importante lembrar que os agentes do sistema podem processar consultas de usuários no servidor para aproveitar os recursos avançados de LLM.
Para oferecer uma ótima experiência do usuário que também evite expor informações sensíveis, recomendamos seguir estas diretrizes:
- Funcionalidade que se beneficia da linguagem natural: disponibilize tarefas que sejam mais fáceis de expressar em uma conversa do que pela navegação manual na interface.
- Acesso restrito: crie AppFunctions que dão ao agente acesso apenas aos dados e às ações necessários para atender à solicitação específica do usuário.
- Informações não sensíveis: compartilhe apenas dados que não sejam altamente pessoais ou confidenciais ou dados que o usuário consente explicitamente em compartilhar no contexto da ação.
- Confirmação inequívoca para qualquer ação destrutiva: tenha muito cuidado com funções que realizam ações destrutivas, como excluir dados. Embora o agente possa invocá-las, seu app precisa incluir uma etapa de confirmação própria e usar uma linguagem clara e inequívoca sobre as intenções. Também é útil adicionar mais de uma etapa de confirmação para garantir que o usuário esteja ciente do que está sendo solicitado.
Verificar a integração do AppFunction
Para verificar se você integrou as AppFunctions corretamente, use adb
shell cmd app_function.
Use adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName para ver detalhes das AppFunctions que seu app oferece.
Também é possível executar uma AppFunction diretamente na linha de comando usando o
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 testar o MCP do Android em ação e verificar fluxos de trabalho completos sem precisar de comandos, instale e execute o agente de teste do AppFunctions app Android no seu dispositivo.
Se você estiver verificando sua integração usando assistentes baseados em chat, como o Gemini no Android Studio, use a habilidade de desenvolvimento do AppFunctions ou forneça um comando como este:
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.
Migrar de versões anteriores da API
Na versão 1.0.0-alpha10, as AppFunctions introduziram uma arquitetura @AppFunctionServiceEntryPoint
em tempo de compilação que consolida as dependências de biblioteca
e substitui os provedores de configuração legados
(AppFunctionConfiguration.Provider).
Se o app usa uma versão anterior do AppFunctions (como
1.0.0-alpha09), é possível automatizar a migração usando a habilidade do agente
do AppFunctions em um ambiente de desenvolvimento integrado de IA, como o Gemini no Android Studio. A habilidade contém
regras de migração dedicadas que orientam um agente a consolidar as dependências de build,
criar o wrapper de serviço @AppFunctionServiceEntryPoint necessário,
desacoplar parâmetros de contexto e atualizar as declarações de manifesto.
Habilidades do Android
Ver no GitHubImplementar AppFunctions
android skills add 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.