本指南介绍了如何将 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 逻辑的类。这涉及为参数和响应创建可序列化的数据类,然后在函数方法中提供核心逻辑。
以下代码展示了在待办事项应用中创建任务的实现示例,包括定义自定义参数和响应类型,以及使用代码库的主函数逻辑。
@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 } }
有关要提供的功能类型的注意事项
安全始终是重中之重。在选择要将应用的哪些功能作为 AppFunction 提供时,请务必注意,系统代理可能会在服务器上处理用户查询,以利用高级 LLM 功能。
为了提供出色的用户体验,同时避免泄露敏感信息,我们建议您遵循以下准则:
- 受益于自然语言的功能:提供用户在对话中比通过手动界面导航更容易表达的任务。
- 限制访问权限:创建 AppFunctions,仅向代理授予访问权限,使其能够访问满足用户特定请求所需的数据和操作。
- 非敏感信息:仅分享非高度个人化或机密的数据,或用户在操作上下文中明确同意分享的数据。
- 对任何破坏性操作进行明确确认:对于执行破坏性操作(例如删除数据)的函数,请务必谨慎。虽然代理可能会调用这些操作,但您的应用应包含自己的确认步骤,并使用清晰、明确的语言说明意图。此外,添加多个确认步骤也有助于确保用户真正了解系统要求他们执行的操作。
验证 AppFunction 集成
如需验证您是否已正确集成 AppFunctions,可以使用 adb
shell cmd app_function。
使用 adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName 查看应用提供的 AppFunctions 的详细信息。
您还可以使用 AppFunction 的显式标识符 ("$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\"}}'"
如需体验 Android MCP 的实际运行情况并验证端到端工作流,而无需任何提示,请在设备上安装并运行 AppFunctions 测试代理 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 skills
在 GitHub 上查看实现 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.