本指南介绍了如何将 AppFunctions API 集成到 Android 应用中、实现函数逻辑,以及验证集成是否正常运行。
版本兼容性
此实现要求您的项目 compileSdk 设置为 API 级别 36 或更高级别。
您的应用无需验证是否支持 AppFunctions;此操作会在 AppFunctions Jetpack 库中自动处理。
AppFunctionManager 如果支持该功能,会返回一个实例;
如果不支持,则返回 null。
依赖项
将所需的库依赖项添加到模块的 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. */ @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) }
代码要点
- 默认情况下,AppFunction 实现会在 Android 界面线程中运行。
因此,长时间运行的操作应执行以下操作:
- 将 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,智能系统可以准确了解用户在任何给定时间可以使用哪些功能。
如需安全地控制需要特定账号状态的 AppFunctions,请按以下两步流程操作:
第 1 步:默认停用该函数
为防止在验证功能标志之前访问该函数,请将 @AppFunction 注解的 isEnabled 参数设置为 false。
@AppFunction(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 } }
考虑要提供的功能类型
安全始终是重中之重。在选择要作为 AppFunctions 提供的应用功能时,请务必记住,系统代理可能会在服务器上处理用户查询,以利用高级 LLM 功能。
为提供出色的用户体验,同时避免泄露敏感信息,我们建议您遵循以下准则:
- 受益于自然语言的功能:提供用户在对话中比通过手动界面导航更容易表达的任务。
- 缩小访问权限:创建 AppFunctions,仅向代理授予完成用户特定请求所需的 数据和操作的访问权限。
- 非敏感信息:仅共享非高度个人 或机密的数据,或用户明确同意在 操作上下文中共享的数据。
- 针对任何破坏性操作的明确确认:对于执行破坏性操作(例如删除 数据)的函数,请格外 谨慎。虽然代理可能会调用这些函数,但您的应用应包含自己的确认步骤,并使用清晰明确的语言说明意图。 添加多个确认步骤也有助于真正确保用户了解系统要求他们执行的操作。
验证 AppFunction 集成
如需验证是否已正确集成 AppFunctions,您可以使用 adb
shell cmd app_function。
使用 adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName 查看应用提供的 AppFunctions 的详细信息。
您还可以使用其
显式标识符 ("$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 testing agent 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 代理
技能自动执行迁移。该技能包含专用迁移规则,可引导代理整合 build 依赖项、创建所需的 @AppFunctionServiceEntryPoint 服务封装容器、分离上下文参数,以及更新清单声明。
Android 技能
在 GitHub 上查看实现 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.