借助 AppFunctions,您的 Android 应用可以共享特定功能,供系统和各种 AI 代理及助理发现和调用。通过定义这些函数,您可以让应用向 Android OS 提供服务、数据和操作,从而让用户能够通过 AI 智能体和系统级互动完成任务。
AppFunctions 相当于 Model Context
Protocol (MCP) 中的移动版工具。MCP 传统上用于标准化代理连接到服务器端工具的方式,而 AppFunctions 为 Android 应用提供了相同的机制。这样,您就可以将应用的能力公开为可编排的“工具”,供获授权的应用(调用方)发现和执行,以满足用户意图。调用方必须具有
EXECUTE_APP_FUNCTIONS权限才能发现和执行 AppFunctions,
并且可以包括代理、应用和 AI 助理(例如 Gemini)。
AppFunctions 适用于搭载 Android 16 或更高版本的设备。
用例示例
AppFunctions 提供了一种强大的机制来自动执行任务并��化用户互动。通过公开应用的功能,您可以让用户使用自然语言完成复杂的目标,通常无需使用界面进行逐步手动导航。
以下场景说明了如何使用 AppFunctions 来提升各种应用类别中的体验:
- 任务管理和效率
- 用户请求:“提醒我今天下午 5 点在工作地点取包裹”。
- AppFunction 操作:调用方会识别相关的任务管理 应用,并调用一个函数来创建任务,根据用户提示自动����� 标���、时间和位置字段。
- 媒体和娱乐
- 用户请求:“创建包含今年最热门爵士专辑的新播放列表”。
- AppFunction 操作:调用方会在音乐应用中执行播放列表创建函数 ,传递“2026 年最热门爵士专辑”等上下文作为 查询,以立即生成和启动内容。
- 跨应用工作流
- 用户请求:“从 Lisa 的电子邮件中找到面条食谱,并将配料添加到我的购物清单中”。
- AppFunction 操作: 此请求使用来自多个应用的函数。 首先,调用方使用电子邮件应用的搜索功能来检索内容。然后,它会提取相关配料,并调用购物清单应用的函数来填充用户的清单。
- 日历和日程安排
- 用户请求:“将妈妈的生日派对添加到我下周一 下午 6 点的日历中”。
- AppFunction 操作:获批准的代理应用会调用日历应用的 “创建活动”函数,解析“下周一”和 “下午 6 点”等相关上下文,以创建条目,而无需用户手动打开 日历。
AppFunctions 的运作方式
AppFunctions 是一项 Android 16 平台功能,也是一个配套的 Jetpack 库,可让应用公开特定函数,供代理应用等调用方 在设备上访问和执行。
下图说明了应用如何将 AppFunctions 共享给代理并随后执行的典型流程。代理在处理用户请求时,可能会同时考虑服务器端远程 MCP 工具和本地 AppFunctions。使用本地 AppFunctions 的详细流程如下:
- AppFunction 声明:Android 应用构建为公开其 AppFunctions,例如“创建笔记”或“发送消息”。
- 架构生成:AppFunctions Jetpack 库会生成一个 XML 架构文件,其中列出了应用中的所有已声明 AppFunctions。Android OS 使用此文件为可用的 AppFunctions 编制索引。
- 元数据检索:代理可以通过 查询来检索 AppFunction 元数据。
- AppFunction 选择和执行:根据用户提示,代理将 选择并执行具有相应 形参的相应 AppFunction。
AppFunctions Jetpack 库简化了应用功能的公开。
借助注解处理器,开发者可以为要公开的函数添加注解。然后,调用方可以使用
AppFunctionManager发现和调用这些已编制索引的函数。
在调用函数之前,调用方应尝试检索 AppFunctionManager 的实例,以验证设备是否支持 AppFunctions 功能。如果支持,调用方可以使用
isAppFunctionEnabled(packageName, functionId)验证目标应用中是否启用了特定
函数。查询其他软件包中
函数的状态需要
android.permission.EXECUTE_APP_FUNCTIONS permission。
您的应用无需验证是否支持 AppFunction 功能;此操作会在 Jetpack 库中自动处理。例如, AppFunctionManager 可以验证是否支持该功能。
以下是笔记应用 AppFunctions 的示例,该应用具有创建、修改和列出笔记的功能。
/** * A note app's [AppFunction]s. */ class NoteFunctions( private val noteRepository: NoteRepository ) { /** * Lists all available notes. * * @param appFunctionContext The context in which the AppFunction is executed. */ @AppFunction(isDescribedByKDoc = true) suspend fun listNotes(appFunctionContext: AppFunctionContext): List<Note>? { return noteRepository.appNotes.ifEmpty { null }?.toList() } /** * Adds a new note to the app. * * @param appFunctionContext The context in which the AppFunction is executed. * @param title The title of the note. * @param content The note's content. */ @AppFunction(isDescribedByKDoc = true) suspend fun createNote( appFunctionContext: AppFunctionContext, title: String, content: String ): Note { return noteRepository.createNote(title, content) } /** * Edits a single note. * * @param appFunctionContext The context in which the AppFunction is executed. * @param noteId The target note's ID. * @param title The note's title if it should be updated. * @param content The new content if it should be updated. */ @AppFunction(isDescribedByKDoc = true) suspend fun editNote( appFunctionContext: AppFunctionContext, noteId: Int, title: String?, content: String?, ): Note? { return noteRepository.updateNote(noteId, title, content) } } /** * A note. */ @AppFunctionSerializable(isDescribedByKDoc = true) data class Note( /** The note's identifier */ val id: Int, /** The note's title */ val title: String, /** The note's content */ val content: String )