0%

把 App 变成 AI 的智能体工具箱:Android 16 AppFunctions 框架详解

当一个 AI 助手想要帮用户”在待办应用里创建一条下午 5 点去公司取快递的提醒”时,传统做法是让助手模拟点击:打开应用、找到添加按钮、填入标题、设置时间、选择地点,然后祈祷 UI 没有改版。这条路径脆弱、缓慢,且无法保证结果。

Android 16 引入的 AppFunctions 框架换了一个思路:**让 App 直接把 createTask() 这样的函数暴露成 AI 可调用的”工具”**,助手传结构化参数、拿结构化返回值,全程本地调用、零网络往返。Google 在官方文档中将其定位为”移动端的 MCP”——App 行为像一台设备端 MCP 服务器,向 Gemini 等 Agent 贡献可编排的工具。

本文基于 2026 年 8 月的官方文档(最后更新 2026-08-09)与 Jetpack androidx.appfunctions 1.0.0-alpha10(2026-07-01 发布)实测核验,系统拆解 AppFunctions 的架构、核心 API、完整实现路径与选型决策。截至 2026 年 5 月,AppFunctions 与 Gemini 的端到端集成仍处于可信测试人员私有预览阶段,但框架 API 与开发工具已可使用。需要注意的是,该库仍处于 alpha 阶段,API 表面迭代频繁——alpha10 相比 alpha08 就引入了 AppFunctionServiceEntryPoint、searchAppFunctions 等变更,文中的代码示例应结合官方最新发布说明使用。

Key Takeaways

  • AppFunctions 是移动端 MCP:Android 16 平台 API + Jetpack 库,让 App 成为 on-device MCP server,向 AI Agent 暴露可发现、可执行、带结构化 schema 的函数工具。
  • 核心机制是注解驱动:用 @AppFunction(isDescribedByKDoc = true) 标记 suspend 函数,KSP 编译时生成 XML schema,Android OS 内置注册表索引,Agent 通过 AppFunctionManager 发现并执行。
  • 本地调用、权限受控:跨 App 执行需要 EXECUTE_APP_FUNCTIONS 权限,函数受 AppFunctionState.isEnabled 控制,App 自身执行自己的函数无需额外权限。
  • 落地前提是架构解耦:AppFunctions 直接调用业务逻辑而非 UI,若核心功能只挂在 Activity/Fragment 上,真正的改造工作是把 repository 层抽成可独立调用。

AppFunctions 是什么:移动端 MCP 的 Android 答案

Model Context Protocol(MCP)在 2024 年底由 Anthropic 推出后,迅速成为 AI Agent 连接外部工具的事实标准。但 MCP 的传统形态是服务器端的——Agent 通过网络连接一个远程 MCP server 调用其工具。这在桌面场景成立,在移动端却有一个根本问题:用户手机上的 App 能力无法通过远程服务器暴露,强行走网络既慢又泄露隐私。

AppFunctions 填的正是这个空缺。Google 在官方文档中明确写道:

AppFunctions 是一个 Android 平台 API,并配有相应的 Jetpack 库,旨在简化 Android MCP 集成。它能赋予你的应用强大的能力,使其像设备端 MCP 服务器一样运作。

这意味着 App 不需要部署任何远程服务。它在本进程内定义函数,编译时生成 schema,系统在设备上索引这些函数。当 Gemini 或其他授权 Agent 需要调用时,走的是本地进程间通信,零网络往返。9to5Google 在 2026 年 2 月 25 日的报道中评价:这与五年前把语音识别搬到设备端是同一级别的架构转移——开发者谁先交付,谁就占据下一代的 Agent 入口。

关于 AI Agent 接入可验证的 Android 开发流程 的完整实践,可参阅此前的 Android CLI 与 Android Skills 最佳实践一文。

下面这张图展示了 AppFunctions 从暴露到执行的完整流程:

AppFunctions 从暴露到执行的完整流程 展示 AppFunctions 四阶段流程:Provider App 用 @AppFunction 注解标记函数,KSP 编译期生成 XML Schema,Android 16 OS 内置注册表索引,Agent 通过 AppFunctionManager 本地执行,零网络往返。 ① Provider App @AppFunction suspend fun createTask() KDoc 描述参数与返回 ② KSP 编译期 生成 XML Schema 函数名/参数/类型/描述 ③ OS 注册表 Android 16 内置 索引所有 App 函数 ④ Agent / 调用方 AppFunctionManager .executeAppFunction() Gemini / 其他授权 App ⑤ 本地 IPC 执行 · 零网络往返 函数在 Provider App 进程的 AppFunctionService 中运行

注解标记
schema 生成
索引注册
Agent 可同时考虑远程 MCP 工具与本地 AppFunctions

AppFunctions 从暴露到执行的完整流程(基于 Android 官方文档架构图重绘)

理解了这张流程图,就能把握 AppFunctions 的本质:它把”App 能做什么”从 UI 背后提到编译期可描述、运行时可发现、调用时可执行的层面。

核心架构与组件体系

AppFunctions 的组件分两层:平台 API(android.app.appfunctions,Android 16 内置)负责系统级注册、发现与执行;Jetpack 库(androidx.appfunctions)负责用注解简化开发体验。两者关系如下:

AppFunctions 两层架构:平台 API 与 Jetpack 库 展示 AppFunctions 的两层架构:上层 Jetpack 库含 @AppFunction 注解、AppFunctionService、AppFunctionConfiguration,封装下层平台 API 含 AppFunctionManager、ExecuteAppFunctionRequest/Response、AppFunctionMetadata。 Jetpack 层 · androidx.appfunctions(开发体验) @AppFunction @AppFunctionSerializable 注解 + KSP 编译器 AppFunctionService AppFunctionContext 函数宿主与执行上下文 AppFunctionConfiguration .Provider DI 工厂注册 三个 artifact appfunctions -service / -compiler

↓ 封装简化 ↓

平台 API 层 · android.app.appfunctions(Android 16 系统服务) AppFunctionManager 系统服务入口 发现/执行/状态 ExecuteAppFunction Request/Response 请求与响应载体 AppFunctionMetadata AppFunctionState 元数据与运行时状态 AppFunctionSearchSpec RegisterAppFunctionRequest AppFunctionException
AppFunctions 两层架构:Jetpack 库封装平台 API,开发者主要接触上层

平台层的关键类(android.app.appfunctions 包):

  • AppFunctionManager:系统服务入口,提供 executeAppFunction()、getAppFunctionStates()、isAppFunctionEnabled() 等方法,是调用方发现和执行函数的唯一通道。
  • ExecuteAppFunctionRequest / ExecuteAppFunctionResponse:请求与响应载体。Request 通过 Builder 构建,需指定 targetPackageName 和 functionIdentifier。
  • AppFunctionMetadata:描述函数的名称、参数 schema、返回类型等,Agent 依据它判断该函数能否满足用户意图。
  • AppFunctionState:运行时状态,isEnabled 为 true 才允许执行——App 可动态启用/禁用某个函数。
  • AppFunctionException:执行失败的统一异常类型。

Jetpack 层的关键组件(androidx.appfunctions 包)负责把上述底层 API 包装成开发者友好的形态:@AppFunction 注解替代手写 metadata,KSP 编译器自动生成 schema,AppFunctionService 承载函数宿主,AppFunctionConfiguration.Provider 处理依赖注入。Google 在Jetpack 发布说明中明确建议:大多数开发者应通过 Jetpack SDK 而非直接操作平台 API 来构建 AppFunctions。

用 @AppFunction 注解暴露函数:从代码到 Schema

AppFunctions 的开发体验核心是一个注解:@AppFunction。开发者只需在 suspend 函数上标注它,KSP 编译器就会读取函数签名和 KDoc,生成包含参数名、类型、描述的结构化 schema,交由 Android OS 索引。

来看官方文档中反复出现的 createTask 示例,它代表了任务管理类应用最典型的暴露场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.taskapp.appfunctions

import androidx.appfunctions.AppFunctionContext
import androidx.appfunctions.service.AppFunction
import java.time.LocalDateTime

class TaskAppFunctions @Inject constructor(
private val repository: TaskRepository
) {
/**
* Create a new task or reminder with a title, due time, and location.
*
* @param title The descriptive title of the task (e.g., "Pick up my package").
* @param dueDateTime The specific date and time when the task should be completed.
* @param location The physical location associated with the task (e.g., "Work").
* @return The created Task
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun createTask(
context: AppFunctionContext,
title: String,
dueDateTime: LocalDateTime? = null,
location: String? = null,
): Task = repository.createTask(title, dueDateTime, location)
}

这里有几个关键点值得注意。

isDescribedByKDoc = true 这个参数告诉编译器:把函数的 KDoc 注释作为 schema 的 description 字段。**KDoc 不只是给人看的文档,更是 AI 模型读的”工具说明书”**。当 Gemini 要判断”用户想取快递”该调用哪个函数时,它读的正是这段 KDoc。因此参数描述里带上示例值(如 "Pick up my package"、"Work"),能显著提升模型选对函数、填对参数的概率。这把”文档质量”从代码规范问题变成了 Agent 能力问题——函数描述应当进入 Code Review 流程。

返回类型 Task 用 @AppFunctionSerializable 标注,编译器会自动生成它的 schema 序列化逻辑:

1
2
3
4
5
6
7
@AppFunctionSerializable(isDescribedByKDoc = true)
data class Task(
val id: String,
val title: String,
val dueDateTime: LocalDateTime? = null,
val location: String? = null,
)

AppFunctionContext 是运行时注入的执行上下文,提供访问应用资源的能力。函数本身是 suspend 的,意味着可以在协程中执行异步操作(如数据库写入),这与现代 Android 开发范式一致。

YouTube 上有开发者对这套注解机制做了实操演示,可以直观看到编译期生成的 schema 与运行时调用效果:

完整实现步骤:让一个函数可被 Agent 调用

把一个函数从普通 Kotlin 代码变成 Agent 可调用工具,需要五步。下面以一个依赖 Hilt 注入 TaskRepository 的任务应用为例。

Step 1:配置 compileSdk 36 与依赖

AppFunctions 平台 API 在 Android 16(API 36)落地,因此 compileSdk 需设为 36。同时引入三个 Jetpack artifact 并启用 KSP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// build.gradle.kts (app 模块)
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.google.devtools.ksp) // 处理 @AppFunction 注解
}

android {
compileSdk = 36 // Android 16,平台 AppFunctions API 所在
// ...
}

ksp {
arg("appfunctions:aggregateAppFunctions", "true") // 聚合所有模块的函数
}

dependencies {
implementation(libs.androidx.appfunctions) // 核心注解与类型
ksp(libs.androidx.appfunctions.compiler) // 编译期 schema 生成器
// 早期版本需要 appfunctions-service artifact 承载宿主;
// alpha10 引入 AppFunctionServiceEntryPoint 后结构有调整,以官方文档为准
}

对应的 version catalog 条目:

1
2
3
4
5
6
7
8
9
# libs.versions.toml
[versions]
appfunctions = "1.0.0-alpha10"

[libraries]
androidx-appfunctions = { group = "androidx.appfunctions", name = "appfunctions", version.ref = "appfunctions" }
androidx-appfunctions-compiler = { group = "androidx.appfunctions", name = "appfunctions-compiler", version.ref = "appfunctions" }
# alpha10 起 artifact 列表有调整:appfunctions-service 可能合并或重命名,
# 且新增了 appfunctions-testing 测试库,请以官方发布说明为准

Step 2:定义 @AppFunction 函数与 @AppFunctionSerializable 数据类

即上一节的 createTask 函数与 Task 数据类。这里强调一个架构前提:函数体内直接调用 repository.createTask(),而非启动 Activity 让用户手动操作。这意味着你的业务逻辑必须能脱离 UI 独立运行。如果今天核心功能只挂在 Activity/Fragment 里,真正的改造工作是先把 repository 和 use case 层抽出来。

Step 3:实现 AppFunctionConfiguration.Provider 提供依赖工厂

带依赖(如 TaskRepository)的函数类无法被系统无参实例化,需要通过 AppFunctionConfiguration.Provider 告诉运行时如何创建实例。在 Application 类中实现这个接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@HiltAndroidApp
class TaskApp : Application(), AppFunctionConfiguration.Provider {

@Inject
lateinit var taskFunctions: Provider<TaskAppFunctions>

override val appFunctionConfiguration: AppFunctionConfiguration
get() = AppFunctionConfiguration
.Builder()
.addEnclosingClassFactory(TaskAppFunctions::class.java) {
taskFunctions.get() // Hilt 提供已注入 repository 的实例
}
.build()
}

addEnclosingClassFactory 注册了一个工厂:当系统需要执行 TaskAppFunctions 中的函数时,调用这个 lambda 拿到实例。这里借助 Hilt 的 Provider 延迟获取,确保依赖图完整。

Step 4:AppFunctionService 承载执行

AppFunctionService 是函数实际运行的宿主。Jetpack 库在底层把它与平台 AppFunction 接口对接——当 AppFunctionManager.executeAppFunction() 被调用时,请求路由到对应 App 的 AppFunctionService,在其中执行注解标记的 suspend 函数。开发者通常不需要手写 Service 样板,编译器生成的代码会处理分发。

Step 5:用 ADB 验证注册

部署到 Android 16 设备或模拟器后,用一条命令检查函数是否被系统成功索引:

1
adb shell cmd app_function list-app-functions

输出会列出已注册的函数及其 metadata(函数标识、参数 schema 等)。这是官方文档反复强调的验证手段——在 alpha 阶段,先用 ADB 确认注册成功,再考虑接入 Agent 调用。

关于 Android 设备交互与验证工具 的更多用法,可参阅 Android CLI 相关实践一文。

发现与执行:Agent 如何调用你的函数

站在调用方(Agent 或其他授权 App)的视角,调用一个 AppFunction 分三步:获取管理器、验证可用性、执行请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 1. 获取 AppFunctionManager,null 表示设备不支持
val manager = context.getSystemService(AppFunctionManager::class.java)
?: return

// 2. 验证目标函数是否启用(跨包查询需 EXECUTE_APP_FUNCTIONS 权限)
manager.isAppFunctionEnabled(
"com.example.taskapp", // targetPackageName
"createTask", // functionIdentifier
executor,
object : OutcomeReceiver<Boolean, Exception> {
override fun onResult(enabled: Boolean) {
if (!enabled) return // 函数被禁用,不可调用
executeTask(manager)
}
override fun onError(error: Exception) {}
}
)

// 3. 构建请求并执行
fun executeTask(manager: AppFunctionManager) {
val request = ExecuteAppFunctionRequest.Builder()
.setTargetPackageName("com.example.taskapp")
.setFunctionIdentifier("createTask")
// .setAttribution(attribution) // 可选:调用归因,未来可能必填
.build()

manager.executeAppFunction(
request,
executor,
null, // CancellationSignal,可取消执行
object : OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> {
override fun onResult(result: ExecuteAppFunctionResponse) {
// 从 result 读取返回的 Task 数据
}
override fun onError(error: AppFunctionException) {
// 处理执行失败
}
}
)
}

权限模型是这个流程的安全基石。官方 API 参考明确:跨组件执行函数,调用方必须持有 EXECUTE_APP_FUNCTIONS 或 EXECUTE_APP_FUNCTIONS_SYSTEM 权限;而 App 执行自己定义的函数不需要任何额外权限。这设计让普通 App 能自调用(例如自己的快捷功能调用自己的函数),同时把跨 App 调用收敛到系统授权的 Agent(如 Gemini)。

AppInteractionAttribution 是一个值得提前关注的字段。ExecuteAppFunctionRequest.Builder 的 setAttribution() 用于声明”谁、为什么”触发了这次调用。官方说明这是当前可选、但未来版本可能变为必填——它服务于隐私透明度,让用户知道某个 App 函数是被哪个 Agent 以什么目的调用的。现在就传入归因信息,能避免后续 API 收紧时的适配成本。

Google I/O 2026 的官方演讲完整演示了从实现 AppFunctions 到用测试 Agent 验证、再到与 Gemini 端到端运行的流程,是理解整套机制最直观的参考:

AppFunctions vs Intent vs App Actions vs MCP:选型对比

Android 上让 App 能力被外部触发的方案不止 AppFunctions 一种。理解它们的边界,才能在合适的场景选对工具。

维度 AppFunctions Intent / DeepLink App Actions (App Actions API) 远程 MCP Server
本质 结构化函数工具,直接调业务逻辑 UI 导航跳转信号 基于 Built-in Intent 的语音/快捷动作 服务器端工具协议
调用方式 AppFunctionManager.executeAppFunction() 传结构化参数 startActivity(intent) Google Assistant 匹配 BII 触发 intent Agent 网络连接 MCP server
输入输出 强类型 schema,结构化请求/响应 额外数据(Bundle),无 schema 约束 intent + 实体参数 JSON schema 工具定义
面向对象 任意授权 Agent / AI 助手 任意 App 主要面向 Google Assistant 任意 MCP 客户端
执行位置 设备本地,零网络往返 设备本地 设备本地 远程服务器
AI 适配度 高:schema + KDoc 天然供模型理解 低:无结构化描述 中:固定 BII 词汇表 高:标准 MCP schema
状态控制 AppFunctionState 动态启用/禁用 无原生运行时开关 无原生运行时开关 由 server 自行控制
引入版本 Android 16(API 36)+ Jetpack 早期 Android Android 5+(App Actions 独立演进) 跨平台,非 Android 专有

关键区别在于抽象层次。Intent 是”打开某个界面”的导航信号,它假设用户接着手动操作;App Actions 把 Intent 包装成语义化的内置动作,但仍落到 Intent 跳转;AppFunctions 彻底跳过 UI 层,直接调用 repository 级别的函数,输入输出都是结构化数据。这使得 AI Agent 无需”看懂”界面就能完成任务。

远程 MCP 与 AppFunctions 不是竞争而是互补。Google 官方指出,Agent 在处理用户请求时会同时考虑远程 MCP 工具和本地 AppFunctions:需要云端数据或算力时走远程 MCP,需要操作用户手机上的 App 时走本地 AppFunctions。一个日程应用完全可以同时暴露”查询云端会议列表”(远程 MCP)和”在本地日历创建事件”(AppFunctions),让 Agent 组合编排。

关于 App 与 AI Agent 协作的工程化实践,可参阅 Android CLI 与 Skills 最佳实践一文。

现状与落地建议

AppFunctions 目前处于 alpha 阶段,几个事实需要正视。

Jetpack 库仍在快速迭代。androidx.appfunctions 从 2025 年 6 月的首个 alpha02 到本文写作时的 alpha10(2026-07-01),API 表面多次调整——AppFunctionSerializable、AppFunctionPrimitiveTypeMetadata、AppFunctionManagerCompat 等在早期版本引入,而 alpha10 又带来了 AppFunctionServiceEntryPoint、searchAppFunctions、AppFunctionInstruction 等新 API,连 artifact 列表都有变化(新增 appfunctions-testing 测试库)。直接用于生产需要做好跟随升级的准备。

端到端 Agent 体验尚未开放。官方文档说明,截至 2026 年 5 月,AppFunctions 与 Gemini 的集成面向可信测试人员私有预览。普通开发者现在能做的是实现函数、用 ADB 验证注册,但还无法让 Gemini 真正调用。Google 设有早期体验计划(EAP),登记意向后有机会被选入端到端测试。

现在该做什么? 趁框架定型前做架构准备,是性价比最高的投入。核心动作就一条:审视你的 App,把需要暴露给自动化的功能,从 Activity/Fragment 下沉到可独立调用的 repository 和 use case。一个判断标准是——如果去掉所有 UI,这个功能能否通过 repository 单独完成?能,就具备了暴露为 AppFunction 的前提;不能,就先重构。这层解耦无论 AppFunctions 是否普及,都是健康的架构演进。

同时可以建立”文档即工程”的意识。既然 KDoc 直接决定 AI 能否正确理解和调用函数,函数描述、参数示例值就该纳入 Code Review,像对待公开 API 文档一样对待它们。

常见问题

AppFunctions 支持哪些 Android 版本?

AppFunctions 平台 API 要求 Android 16(API level 36)或更高版本。Jetpack 库的 minSdk 可以设得更低以兼容编译,但运行时只有 Android 16 设备才会真正索引和执行函数。调用方应先通过 getSystemService(AppFunctionManager::class.java) 返回是否为 null 来判断设备支持情况。

AppFunctions 和 App Actions 有什么区别?

App Actions 基于 Built-in Intent(BII),面向 Google Assistant,本质还是触发 Intent 跳转到 Activity,依赖 UI 流程。AppFunctions 跳过 UI,直接调用结构化函数,输入输出有 schema,面向任意授权 Agent。前者是”用语音打开界面”,后者是”用 AI 调用功能”。

普通开发者现在能用 AppFunctions 吗?

可以实现并验证,但端到端 Agent 调用尚未开放。开发者现在能做的是:按本文步骤实现 @AppFunction 函数,部署到 Android 16 设备,用 adb shell cmd app_function list-app-functions 确认注册成功。让 Gemini 等系统 Agent 真正调用,需等待正式发布或申请加入 EAP。

AppFunctions 必须依赖 Gemini 吗?

不是。AppFunctions 是通用的函数暴露框架,任何持有 EXECUTE_APP_FUNCTIONS 权限的 App 都能通过 AppFunctionManager 发现和执行。Gemini 只是首个系统级消费者。理论上其他 AI 助手、自动化工具甚至普通 App 都可以成为调用方——这正是 Google 把它定位为”移动端 MCP”而非”Gemini 专用接口”的原因。

结论

AppFunctions 的价值不在于多了一个 API,而在于它重新定义了 App 与 AI Agent 的协作边界:App 不再只是被打开的界面,而是贡献结构化工具的设备端 MCP server。

回顾要点:

  • 定位:移动端 MCP,App 作为 on-device MCP server,本地调用、零网络往返。
  • 机制:@AppFunction 注解 + KSP 编译期生成 schema + OS 内置注册表索引 + AppFunctionManager 发现执行。
  • 前提:业务逻辑与 UI 解耦,repository 可独立调用;KDoc 作为 AI 可读文档需纳入工程规范。
  • 节奏:框架 alpha 阶段、Gemini 集成私有预览,现在做架构准备性价比最高。

对于专注 Android 的开发者,这波 Agent 化浪潮和当年从命令行到 GUI、从单机到云端的转变同级。提前把 App 的能力原子化、可描述化,是在为下一轮交互范式占位。当 Gemini 或其他 Agent 真正向所有 App 开放调用时,架构已就绪的人会最先吃到红利。

更多 AI Agent 与 Android 工程化实践,敬请关注后续 AppFunctions 实战系列更新。