欢迎回到“打造智能 Android 应用”系列博文。我们将在此系列博文中介绍如何将基本的 Android 应用转变为个性化、智能化和智能体化的体验。在上一篇博文中,我们探讨了如何利用 Firebase AI Logic 构建云托管型和混合型 AI 功能。
传统移动界面擅长处理专注的动手操作任务,而 Android 智能系统正在引入补充功能,以使复杂的多步骤操作更加轻松。通过补充传统的用户界面,AppFunction 提供了一个强大的新入口点:设备上的特权代理可以在后台访问应用功能。当用户驾车、走路或同时处理多项任务时,此功能会特别有用。
在本文中,我们将向您展示如何使用 Android AppFunctions 将这些功能设计并集成到我们的旅行规划应用 JetPacker 中。我们将探讨我们选择这些功能的理由,讨论我们用于加速开发的专用工具,并深入了解使这一切正常运行的代码。
设计 AI 就绪型功能:做出对用户至关重要的选择
为了选择要向智能系统提供的功能,我们寻找了语音或文本指令在客观上比通过点按屏幕更快完成的任务。在此并排屏幕录制视频中,您可以清楚地看到这种对比:左侧,用户通过点按多个屏幕来记录费用;右侧,通过特权代理在后台立即完成同一任务。
我们首先选择的是费用跟踪。在旅途中记录咖啡费用通常需要多次点按:解锁手机、打开应用、找到有效行程、前往“费用”标签页、点按“添加”按钮、拍摄收据照片,然后检查结果。通过将 addExpense 和 getExpenses 功能作为 AppFunctions 提供,系统代理可以处理繁重的工作。当用户说“在我的巴黎之旅中添加一笔 5 美元的咖啡费用”时,代理会在后台自动搜索正确的旅行 ID 并插入费用,完全跳过手动界面流程。
我们还优先考虑了行程管理。在繁忙的行程安排中查找下一个活动通常需要滚动浏览密密麻麻的时间轴视图。通过向系统提供 getItinerary 和 addItineraryEvent,用户只需询问“接下来在巴黎要做什么?”,即可立即获得答案。
最后,我们重点介绍了免手动操作的笔记记录功能。在繁忙的街道上行走时,输入提醒或记事既困难又不安全。公开语音记事功能后,用户可以说“这次航班太棒了,我看到了美丽的日落,而且睡得很好”,然后特权代理会自动转写该语音记事,并使用 addVoiceNote AppFunction 将其直接保存到旅游数据库中。
由 AppFunctions 提供支持的 Android MCP
整个体验基于 Android MCP 构建。在此设计下,应用充当本地 MCP 服务器。您无需使用远程 API,而是直接向设备端智能系统提供应用功能。
Android AppFunctions API 可让这一概念成为现实。它会读取带注释的 Kotlin 函数,并将其编译为类型安全、沙盒化的工具定义,特权代理可以在设备上发现并本地调用这些工具。
在 Android MCP 模型下,您的应用充当公开结构化工具的本地 MCP 服务器,而 Android 平台则充当中央工具注册表。在 MCP 客户端,代理应用在获得访问注册表的系统特权权限后,会注册到智能系统。
当用户与已注册的代理互动时,该代理的 LLM 会确定请求是否可由 AppFunction 处理,查询平台的元数据,并在后台执行相应的已注册函数。这种本地 MCP 客户端-服务器设计让您拥有完全控制权:您可以准确选择智能体可访问的功能,同时确保应用的其他数据保持私密。
我们如何利用 Android 技能加速开发
为了简化集成流程,我们利用了 AppFunctions 开发技能。AppFunctions 开发技能是一套完整的开发助手。它引导我们完成了整个生命周期:将 Kotlin 数据类映射到序列化参数、生成必要的 Service 入口点、完善 KDoc 文档以确保 LLM 了解参数边界,以及使用 ADB 设置自动化测试。
向智能系统提供应用功能
理论就讲到这里,我们来深入了解一下实现过程。
配置和依赖项设置
我们首先添加 AppFunctions 依赖项。一个用于 API,另一个用于 Kotlin Symbol Processing 编译器。
implementation("androidx.appfunctions:appfunctions:1.0.0-alpha10")
ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha10")对自定义数据类型进行建模
与代理交换的任何自定义对象都必须使用 @AppFunctionSerializable 进行注释。在 TripSerializable.kt 文件中,我们定义了行程数据模型:
@AppFunctionSerializable(isDescribedByKDoc = true) data class TripSerializable( /** The trip's unique identifier. */ val id: String, /** The trip's title. */ val title: String, /** The trip's destination location. */ val location: String, /** The trip's start date in milliseconds. */ val startDate: Long, /** The trip's end date in milliseconds. */ val endDate: Long, /** A list of participants. */ val participants: List<String>, )
使用 @AppFunction 注释提供功能
接下来,技能编写了执行数据库查询的 Kotlin 函数,并使用 @AppFunction 对这些函数进行了注释。我们可以在 searchTrip 中查看此内容:
/** * Looks for trips based on optional filters like id, title (name), location, and dates. * * @param id The unique identifier of the trip. * @param title The title or name of the trip. * @param location The destination location. * @param startDate The minimum start date in milliseconds. * @param endDate The maximum end date in milliseconds. * @return A list of trips matching the filters. */ @AppFunction(isDescribedByKDoc = true) suspend fun searchTrip( id: String? = null, title: String? = null, location: String? = null, startDate: Long? = null, endDate: Long? = null ): List<TripSerializable> { return withContext(Dispatchers.IO) { // implementation }
由于 AppFunctions 默认在界面线程上运行,因此我们使用 withContext(Dispatchers.IO) 切换到后台调度程序。此外,我们还改进了 KDoc,使其使用清晰的命令式动词并指定参数限制。此文档直接编译到工具的架构中,特权代理使用该架构来解析参数和处理运行时错误。
服务入口点和 Hilt 集成
为了向智能系统注册这些功能,我们创建了一个扩展 AppFunctionService 的抽象基类。我们使用 @AppFunctionServiceEntryPoint 为其添加注解:
@RequiresApi(36) @AndroidEntryPoint @AppFunctionServiceEntryPoint( serviceName = "JetPackerAppFunctionService", appFunctionXmlFileName = "jetpacker_app_function_service" ) abstract class BaseJetPackerAppFunctionService : AppFunctionService() { @Inject internal lateinit var tripDao: TripDao // DAOs and database references are injected here... }
在编译期间,KSP 会生成最终的具体服务子类 JetPackerAppFunctionService,如 serviceName 参数所声明的那样。我们还在应用的清单中注册了 app_metadata.xml。此文件为 JetPacker 声明的 AppFunction 提供全局操作规则。
测试和验证 AppFunctions
实现后,您应验证 AppFunction 是否已注册并正常运行。
如果运行的是搭载 Android 17 或更高版本的设备或模拟器,您可以使用终端中的 ADB 命令列出并调用函数。运行 adb shell cmd app_function list-app-functions 会显示软件包的所有已注册函数。然后,您可以运行 adb shell cmd app_function execute-app-function 并传递原始 JSON 参数字符串,以执行特定函数并测试其数据库集成。
除了这些 ADB 命令之外,您还可以使用 AppFunctions 测试代理来检查配置、列出和执行 AppFunctions,甚至查看 AppFunctions 在实际对话流程中的行为。
总结
在考虑可以使用 AppFunctions 为智能系统贡献的应用功能时,我们需要稍微改变一下对代码和文档的思考方式。借助 AppFunctions,您可以为应用使用这种新的互动模式,从而允许使用智能体来访问应用功能。
首先,AppFunctions 开发技能是一项重要的生命周期工具,可帮助您发现功能、为应用实现和优化 AppFunctions。其次,KDoc 注释是已编译的 API 资源;清晰的参数说明会直接影响系统代理的执行准确性。最后,Android MCP 提供本地优先执行,使应用能够安全地与 AI 代理协作。
通过 AppFunctions 贡献应用功能可让您的应用为智能系统做好准备。欢迎告诉我们您如何让应用适应智能体时代!
了解详情
不妨查看此博文系列的其余部分:
第 1 部分:应用简介和高级概览。
第 2 部分:设备端智能。深入了解 ML Kit 的生成式 AI API 和 Gemini Nano,打造以隐私保护为先的功能,例如行程摘要、收据解析和本地音频处理。
第 3 部分:混合推理和云端推理。了解如何使用 Firebase AI Logic 让 LLM 回答依托 Google 地图和网络上下文等真实世界的数据。
第 4 部分(本文!):系统集成。使用 AppFunctions 与 Android 智能系统集成。
第 5 部分(即将推出):应用内智能体工作流。使用 A2UI 和 ADK 扩展应用,使其具备端到端预订助理功能。
有兴趣了解更多 Android 开发方面的内容?欢迎在 YouTube 或 LinkedIn 上关注 Android 开发者!
本博文中的所有代码段均遵循以下版权声明:
Copyright 2026 Google LLC. SPDX-License-Identifier: Apache-2.0
-
方法指南欢迎回到“打造智能 Android 应用”系列博文,我们将在此系列博文中介绍如何将基本的 Android 应用转变为个性化、智能化和智能体化的体验。在之前的博文中,我们介绍了 Jetpacker,这是我们将在本系列文章中使用的演示版应用。
Caren Chang • 阅读用时:6 分钟 -
方法指南Jetpacker 是一款技术展示应用,由我们的团队从头开始构建,用于今年的 Google I/O 大会(使用 Antigravity 构建)。Jetpacker 的核心功能是帮助用户规划、探索和享受下一次精彩的冒险之旅。
Jolanda Verhoef • 阅读用时:4 分钟 -
方法指南欢迎回到“打造智能 Android 应用”系列博文,我们将在此系列博文中介绍如何将基本的 Android 应用转变为个性化、智能化和智能体化的体验。
Thomas Ezan, Jolanda Verhoef, Caren Chang • 阅读用时:8 分钟
每周通过电子邮件接收最新的 Android 开发洞见。