Google Jetpack AppFunctions 完整介绍
Android 16 (API36) 新增 Jetpack 组件,Android 本地 MCP 实现 ,让 AI Agent (Gemini) 本地调用 App 内部能力,不用走网络。你项目里 Volvo 的
@AppFunction(isDescribedByKDoc=true)就是参照谷歌原生 AppFunctions 做的内部自研框架,注解名字、参数几乎一模一样,但不是谷歌官方库。
状态:Alpha 预览版,尚未稳定,仅 Android16 + 支持Android De...。
一、核心概念
@AppFunction注解:标记 suspend 函数,把普通 Kotlin 函数暴露给系统 AI 智能体调用。isDescribedByKDoc = true:KSP 编译器读取 KDoc 注释,自动生成 LLM Function‑call 的description、参数说明,不用手写 JSON 工具描述。@AppFunctionSerializable:自定义入参 / 返回数据类,同样支持isDescribedByKDoc=true解析 KDoc。AppFunctionService:系统 Service,接收系统 Agent 的跨进程调用请求,KSP 自动生成子类。- 系统维护全局函数注册表:所有 App 的 AppFunction 元数据注册到 SystemServer;Agent 有权限就可以发现、调用本机所有 App 开放的函数。
类比 MCP:
- 传统 MCP:大模型 ↔ 远端服务器工具
- AppFunctions:Gemini(Agent) ↔ 本机各个 App 本地函数,全部设备内执行,不上传业务数据到云端。
整体调用流程
- 开发者用
@AppFunction标记 suspend 函数,写好 KDoc 注释 - KSP 编译期扫描注解,自动生成:元数据 XML、Service 骨架、序列化代码
- App 安装,XML 注册到 Android 系统 AppFunction 注册表
- Agent (Gemini) 拿到权限,查询系统注册表,获取全部函数 + 工具描述(来自 KDoc)
- LLM 决策调用哪个函数,系统 IPC 唤起目标 App 的
AppFunctionService,执行函数,返回结果给 Agent
二、环境依赖 build.gradle.kts(Module 级别)
需要 KSP,Android16+,Jetpack AppFunctions alpha 库Android De...
kotlin
scss
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp") //必须开启KSP
}
android {
compileSdk = 36 // Android16
defaultConfig {
minSdk = 36
}
}
dependencies {
implementation("androidx.appfunctions:appfunctions:1.0.0‑alpha10")
ksp("androidx.appfunctions:appfunctions‑compiler:1.0.0‑alpha10")
}
三、完整代码示例
1. 定义可序列化数据类(入参、返回值)
kotlin
less
/** 任务实体 */
@AppFunctionSerializable(isDescribedByKDoc = true)
data class Task(
/** 任务唯一ID */
val id: String,
/** 任务标题 */
val title: String,
/** 任务详情内容 */
val content: String
)
/** 创建任务入参 */
@AppFunctionSerializable(isDescribedByKDoc = true)
data class CreateTaskParams(
/** 任务标题,可以为空 */
val title: String?,
/** 任务内容,可以为空 */
val content: String?
)
2. AppFunctionService 基类
@AppFunctionServiceEntryPoint:KSP 基于这个抽象类生成真正的 Android Service 组件,注册到 AndroidManifest。
kotlin
kotlin
@RequiresApi(36)
@AppFunctionServiceEntryPoint(
serviceName = "TaskAppFunctionService",
appFunctionXmlFileName = "task_app_function_service"
)
abstract class BaseTaskAppFunctionService : AppFunctionService() {
/**
* 创建一个待办任务
* @param createTaskParams 创建任务的参数
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun createTask(createTaskParams: CreateTaskParams): Task {
// 业务逻辑,IO操作要放在Dispatchers.IO
if(createTaskParams.title.isNullOrBlank() && createTaskParams.content.isNullOrBlank()){
// 抛出框架预定义异常,Agent可以捕获识别错误原因
throw AppFunctionInvalidArgumentException("标题或内容不能同时为空")
}
return Task(id = "123", title = createTaskParams.title, content = createTaskParams.content)
}
}
⚠️ 强制约束:
@AppFunction只能修饰 suspend 挂起函数,不能普通函数、不能接口方法(Volvo 自研是接口,谷歌原生是 suspend function 写在 Service 内部)- 入参返回值只能是基础类型 /
@AppFunctionSerializable标记 data class,不支持任意对象isDescribedByKDoc=true,才提取 KDoc 生成 LLM 工具描述;false 就忽略注释,description 为空,Agent 无法理解函数用途- 修改 KDoc 注释,必须 Rebuild 项目,增量编译不会重新解析注释
四、Manifest 配置
KSP 自动生成 Service,但需要权限声明:
xml
xml
<!-- 本应用开放AppFunction能力给系统 -->
<uses-permission android:name="android.permission.BIND_APP_FUNCTION_SERVICE"/>
<!-- 调用方Agent(如Gemini)需要这个权限才能发现&执行AppFunctions -->
<uses-permission android:name="android.permission.EXECUTE_APP_FUNCTIONS"/>
注意:
EXECUTE_APP_FUNCTIONS是系统级签名权限,普通第三方 App 拿不到,只有系统 Agent/Gemini 可以拥有。
五、@AppFunction注解全部参数
kotlin
kotlin
annotation class AppFunction(
// true:解析KDoc注释作为LLM工具描述
val isDescribedByKDoc: Boolean = false,
// 是否对外暴露给Agent调用
val isEnabled: Boolean = true
)
六、常见坑点
- 修改 KDoc 注释不生效 :KSP 增量编译不会重新处理注释,执行
Build → Rebuild Project。 - 函数不能是普通 fun,谷歌原生强制 suspend 挂起函数 ,IO 逻辑用
withContext(Dispatchers.IO)。 - 普通第三方 App 不能作为调用端:
EXECUTE_APP_FUNCTIONS是系统权限,只有系统 Agent 可以调用。 - 只能 Android16 以上,低版本系统无法兼容。
- 异常不要抛普通 Exception,要抛框架定义的
AppFunctionInvalidArgumentException等,Agent 可以识别错误码。
七、Agent 调用方简单示意
Agent 拥有系统权限,通过AppFunctionManager查询全部可用函数、执行函数:
kotlin
kotlin
val appFunctionManager = context.getSystemService(AppFunctionManager::class.java)
// 获取所有App暴露的函数元数据(包含从KDoc解析出来的tool description)
val allFunctions = appFunctionManager.getAppFunctions()
// 执行某个function,传入参数
appFunctionManager.executeAppFunction(request, ...)