多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AppActuator - 让 AI Agent 直接理解并操作运行中的 Android App

AppActuator - 让 AI Agent 直接理解并操作运行中的 Android App AppActuator - 让 AI Agent 直接理解并操作运行中的 Android App为什么用它5 分钟接入1. 配置仓库与插件2. 开放一个业务对象3. 构建并确认服务4. 从 PC 调用让 AI Coding 工具直接使用鉴权与正式包安全运行模型与重要限制跑通扫雷 Demo项目结构从源码构建让 AI Agent 直接理解并操作运行中的 Android App而不是隔着屏幕猜测。项目Github地址AppActuator 是一个面向开发与测试场景的 Android 工具库。你可以把少量业务方法显式开放给 AI Agent让它通过adb Socket JSON-RPC 2.0调用方法、读取状态、等待事件。调试包获得完整能力release 包默认替换为空实现并在构建时检查是否剥离干净。AI Agent / MCP Client │ │ JSON-RPC 2.0 over adb forward ▼ ┌──────────────── Android App ────────────────┐ │ AppActuator │ │ 方法注册表 · 事件总线 · 生命周期 · 鉴权加密 │ │ │ │ │ ▼ │ │ 你显式开放的业务对象 │ └─────────────────────────────────────────────┘为什么用它假设你想让 Agent 测试一局扫雷。只靠截图和坐标点击它很难可靠地知道「这一格是否已打开」「还剩多少雷」「游戏何时结束」。AppActuator 让 Agent 在你划定的边界内直接调用game.sweepCell、读取game.getGameState并等待game.gameOver。你通常遇到的问题AppActuator 的做法坐标点击容易受 UI 改版影响直接调用稳定的业务方法截图只能推测内部状态返回结构化 JSON 数据轮询又慢又不可靠App 主动发事件Agent 按需等待自建调试服务容易遗留在正式包release 默认注入 noop并自动审计依赖、Manifest 和 DEX暴露范围难以控制只有显式注解且注册的方法可以被调用它适合调试诊断、业务级自动化测试、AI Coding 联调、教学 Demo 和内部工具。它不用于跨 App 系统自动化、代码注入、热更新或逆向分析也不替代 UIAutomator/Appium涉及真实用户界面的端到端验证时两类工具可以配合使用。5 分钟接入前置条件AGP 8.x、JDK 17、minSdk 30。插件和 Android 库已发布到 Gradle Plugin Portal / Maven Central。1. 配置仓库与插件宿主工程的settings.gradle.kts需要包含pluginManagement{repositories{gradlePluginPortal()google()mavenCentral()}}dependencyResolutionManagement{repositories{google()mavenCentral()}}然后在应用模块的build.gradle.kts中应用插件plugins{id(io.gitee.kuangthree.appactuator)version0.2.0}appActuator{authdisabled// disabled | optional | requiredautoStarttrue// App 进程启动时自动初始化keepAlivefalse// 默认不在后台保持信道requireShellUidtrue// 仅允许 adb shell 读取元数据}无需手动添加library-api、library-full或library-noop。插件会按构建变体注入正确实现debug 默认使用 fullrelease 默认使用 noop。2. 开放一个业务对象importandroid.app.Applicationimportcom.universe_st.appactuator.api.ActuatorMethodimportcom.universe_st.appactuator.api.ActuatorTargetimportcom.universe_st.appactuator.api.AppActuatorimportcom.universe_st.appactuator.api.ThreadModeActuatorTarget(namegame,description游戏控制器)classGameController{privatefungameRunning():BooleantrueActuatorMethod(namesweepCell,conditiongameRunning,threadThreadMode.MAIN,)funsweepCell(x:Int,y:Int):MapString,Int{valresultmapOf(xtox,ytoy)AppActuator.emit(game.boardChanged,result)returnresult}}classDemoApplication:Application(){overridefunonCreate(){super.onCreate()AppActuator.register(GameController())}}如果项目还没有自定义Application请在AndroidManifest.xml中声明applicationandroid:name.DemoApplication.../这里有三个重要边界只有ActuatorMethod标记的方法会暴露普通方法仍然不可见。condition指向同类中的无参Boolean方法返回false时调用会被拒绝条件方法本身不能再标记ActuatorMethod。ThreadMode.MAIN用于 UI 操作BACKGROUND用于耗时任务默认的CALLER适合快速、无 UI 依赖的方法。3. 构建并确认服务.\gradlew.bat :app:assembleDebug.\gradlew.bat :app:installDebug adb shell content query--uri content://com.example.app.actuator/metadata把com.example.app换成应用的applicationId。正常情况下会看到statusrunning、动态端口、协议版本和鉴权档位。如果 App 被 force-stop先显式启动它如果设备执行过adb root默认的 shell UID 校验会拒绝查询请先adb unroot。4. 从 PC 调用仓库内的 Python 客户端要求 Python 3.10python-m pip install-eclientfromappactuatorimportAppActuatorClient clientAppActuatorClient(packagecom.example.app)try:client.connect()client.handshake()methodsclient.list_methods()resultclient.invoke(game,sweepCell,{x:0,y:0})eventclient.wait_event(game.gameOver,timeout_ms60_000)finally:client.close()list_methods()支持targets只看特定对象如client.list_methods(targets[game.1])也接受类名前缀[game]匹配全部实例与no_desc返回最小结构省 token参数详见skill/app-actuator/SKILL.md。connect()会自动完成元数据查询和adb forward随后由handshake()协商协议close()会同时清理连接与转发。多台设备同时连接时请向客户端传入设备序列号。让 AI Coding 工具直接使用仓库提供两种 Agent 接入方式Agent Skill位于仓库根目录的skill/文件夹适合能读取操作指引并运行命令的 Agent。MCP Server适合支持本地 stdio MCP 的 AI Coding 工具。安装命令为python -m pip install -e client[mcp]启用鉴权时使用client[all]。下面是兼容mcpServers格式的最小配置。路径应替换为本机仓库的绝对路径如果客户端已安装到当前 Python 环境可以移除PYTHONPATH。{mcpServers:{appactuator:{command:python,args:[-m,appactuator.mcp_server],env:{PYTHONPATH:C:/path/to/app-actuator/client,APPACTUATOR_PACKAGE:com.example.app,APPACTUATOR_SERIAL:emulator-5554}}}}MCP Server 暴露固定的 7 个工具避免宿主方法动态变化导致工具缓存失效工具用途actuator_connect建立连接重复调用安全actuator_get_status查看运行状态与鉴权档位actuator_list_methods获取实时方法清单、参数与不可用原因支持targets过滤与no_desc最小结构actuator_invoke调用一个宿主方法actuator_list_events查看已声明或已触发的事件actuator_wait_event等待一次事件actuator_close关闭连接并清理 adb forwardReasonix、OpenCode 等工具的完整配置示例和环境变量说明见 AI Coding MCP 接入文档。鉴权与正式包安全内部调试包也建议使用required鉴权。先生成密钥对$env:PYTHONPATH clientpython-m appactuator.genkey--out-dirkeys公钥随构建注入 App私钥只保留在 PC.\gradlew.bat :app:assembleDebug -PappActuator.authrequired-PappActuator.publicKeyFilekeys/appactuator_public.pem鉴权成功后业务消息使用 AES-256-GCM 加密握手使用 RSA 公钥体系。required模式缺少有效公钥时服务不会启动。PowerShell 中的-PappActuator.keyvalue参数务必整体加引号。release 安全不是一条使用建议而是构建机制插件默认让 release 变体依赖library-noop其公开 API 行为固定为空操作。完整实现使用的 Provider、Service 和INTERNET权限不会由 noop 引入。release 构建自动从依赖图、合并后的 Manifest 和 DEX 三个层面审计残留发现完整实现即构建失败。请勿用-PappActuator.enabledtrue将完整实现带入生产 release。该开关只应服务于明确隔离的内部构建。运行模型与重要限制服务只监听设备回环地址127.0.0.1PC 必须通过 adb 转发访问。单个 App 同时只接受一个客户端连接同一连接内可以并发请求。listMethods和invoke都会实时检查注册状态、生命周期与自定义条件不依赖旧缓存。waitEvent只等待请求发出之后的事件不补发历史事件需要可靠恢复时应同时提供状态查询方法。Kotlin 默认参数不受支持调用方必须显式传入全部参数。同一 target 中的暴露方法不能重名发现重名时整个 target 注册失败。单条消息、并发请求、事件等待与订阅均有资源上限默认调用超时为 30 秒。keepAlivetrue会引入specialUse前台服务及相应政策成本只建议用于内部调试构建。library-full声明INTERNET权限以创建本地 Socket剥离后的 noop 构建不包含该权限。协议、安全与并发语义的权威定义在 需求规格实现追踪和端到端验证记录在 合规矩阵。跑通扫雷 Demo仓库自带一个 10×10 Compose 扫雷 Demo。它开放newGame、getGameState、getCell、sweepCell、toggleFlag和game.*事件是体验完整链路最快的入口。.\gradlew.bat :demo:sweeper:assembleDebug.\gradlew.bat :demo:sweeper:installDebug adb shell content query--uri content://com.universe_st.appactuator.demo.sweeper.actuator/metadata$env:PYTHONPATH clientpython client/examples/sweeper_demo.py --package com.universe_st.appactuator.demo.sweeper需要鉴权时$env:PYTHONPATH clientpython-m appactuator.genkey--out-dirkeys.\gradlew.bat :demo:sweeper:assembleDebug-PappActuator.authrequired-PappActuator.publicKeyFilekeys/appactuator_public.pem.\gradlew.bat :demo:sweeper:installDebug python client/examples/sweeper_demo.py--package com.universe_st.appactuator.demo.sweeper--private-key keys/appactuator_private.pem项目结构路径职责library-api/稳定公开 API注解、门面、配置、错误码与 noop 兜底library-full/Provider、TCP Server、JSON-RPC、注册表、事件与加密鉴权library-noop/release 剥离构建使用的空 AARlibrary-lifecycle/可选 AndroidX Lifecycle 适配plugin/变体依赖注入、构建期配置与剥离审计client/Python 客户端、CLI、密钥工具与 MCP Serverdemo/sweeper/Compose 扫雷示例skill/Agent 操作指引完整实现中的core/与crypto/不依赖android.*因此核心协议和加密逻辑可以直接在 JVM 上测试。公开错误码由 Android 与 Python 两端同步维护。从源码构建需要 JDK 17 和 Android SDK并在local.properties中配置sdk.dir。# Debug 构建注入完整实现.\gradlew.bat :demo:sweeper:assembleDebug# Release 构建注入 noop并运行剥离审计.\gradlew.bat :demo:sweeper:assembleRelease# Android / Gradle 单元测试.\gradlew.bat :library-full:testDebugUnitTest :library-lifecycle:testDebugUnitTest :demo:sweeper:testDebugUnitTest :plugin:test# Python 客户端测试$env:PYTHONPATH clientpython-m unittest discover-s client/tests-v
返回列表