ARTICLE · 1315144
Mika 如何在安卓手机上替你操作 App:从虚拟屏到任务循环

Mika 是一个运行在安卓手机上的 AI 助手。它能把“读完群聊并总结”这类请求拆成一串读屏、点击、输入和核对动作,同时把操作放在另一块虚拟屏上,让用户继续使用主屏。核心思路是:模型决定下一步做什么,程序负责把每一步限制在可检查、可记录的执行路径里。
Mika 项目首页 : https://github.com/wangzan101/Mika
本文依据 Mika 仓库的开发文档和关键源码分析实现。这里的“设备端”指任务调度、界面操作和数据存储主要由手机上的 App 完成;如果配置的是在线模型,任务文字和需要模型理解的界面内容仍会发给所选模型服务商。

封面:任务、虚拟屏与模型之间的关系。自制示意图。
一句话任务怎样变成一串操作
用户发来请求后,安卓侧的 TaskService 把它交给 TaskCenter。后者保证同一个对话同一时间只有一个运行中的任务;不同对话是否并行、超出上限怎样排队,也由这一层处理。一次任务由 RunSpec 描述,包含目标、所属对话、可用能力、是否只读、来源和步数预算等信息。
TaskRun 随后按任务装入手机、网页、沙箱等能力,再启动 AgentLoop。这层循环的工作很单纯:构造上下文,请模型给出回答或工具调用,执行工具,把结果变成新的观察,再问模型下一步。模型直接回复且没有工具调用时,这一轮才进入回答流程;做不成时可以调用 end_not_done,说明已经做了什么、卡在哪里。

图 1:请求进入任务中心后,模型与工具反复交互;每次界面动作都经过统一执行入口。依据仓库架构文档与
AgentLoop.kt、ActionExecutor.kt自制。
这个设计把“规划”和“执行”分开。模型可以提出“点第 3 个按钮”,但不直接拥有触摸屏的通道。ToolDispatcher 按名称和声明找到工具;会改变外部状态的调用,必须从 ActionExecutor 进入。只读入口 executeRead 遇到写工具会拒绝;写入口需要 ActionPass,而这个通行对象只由执行入口创建。手机、网页、复合步骤和回放因此共享一套守卫、审批、执行后核对与记录流程。
工具也不是一次全部塞给模型。开局只给部分入口,例如打开 App、打开网页、运行命令;使用某组能力后,下一次请求才展开这组工具的完整定义。这样能控制固定提示词的体积。do_steps 则允许模型一次提交最多 20 个已知动作,代码逐步执行并等待界面条件成立;弹窗、切换 App 或用户插话时会提前停止后续步骤,避免按过时的计划继续点。
后台操作为什么不占用用户的主屏
手机 App 操作依靠两部分配合:一块独立虚拟屏,以及能在这块屏上读写界面的手机助手。Mika 通过无线调试配对取得连接,内置助手以 Android 的 shell 身份运行。需要操作 App 时,助手创建虚拟显示,并把目标 App 启动到该显示上。安卓 14 起,这块屏通常有自己的输入焦点;安卓 12、13 上,主屏焦点可能短暂受影响。安卓 12 以下不支持这种 App 操作,但聊天、网页等功能仍可用。
虚拟屏的画面输出到 ImageReader。AgentDisplay 从中取最新帧,生成缩小的实时预览;源码把预览处理频率限制在每秒最多 10 帧。截图只是画面来源。实际定位按钮时,Mika 主要使用无障碍控件树,把文字、边界和可执行动作整理成带编号的界面元素;控件树读不到的自绘界面,才补用 OCR 或视觉模型。动作后再读界面,判断文字是否输入成功、页面是否变化、目标是否仍然存在。

图 2:主屏与后台虚拟屏共享一部手机,但目标 App 在另一块显示上运行;图中为结构示意,不代表系统界面截图。依据
AgentDisplay.kt、ShellService.kt及架构文档自制。
这里还有一层容易忽略的系统处理。后台 App 可能播放声音,Mika 会按“应用包名+用户”记录并暂时静音;任务结束时恢复原来的状态。需要用户登录、输入验证码或付款时,它把虚拟屏中的 App 交到主屏,等用户处理后再接回,重新读屏确认当前状态。它没有假设接管期间的页面与交出时完全相同。
浏览网页走的是另一条能力链
网页任务使用 App 内的 WebView,渲染在私有虚拟显示上,不需要前面那套 shell 手机助手。页面操作优先走 WebView 的 DevTools 协议,发送鼠标和键盘输入;连接不可用时,代码会退回页面脚本。Mika 同时读取页面元素、文本和页面收到的数据。下载文件落到当前对话的工作区,上传只从该工作区取文件。
用户也可以在 Mika 内置浏览器里,从自己正在看的页面发起任务。这时任务会“借用”当前标签:保留登录、滚动和表单状态,在原页面继续工作。用户用手触碰该页面,任务会暂停;继续按钮解除暂停。借用标签和任务自己新开的后台标签由同一套网页工具操作,但生命周期不同。

图 3:手机能力使用虚拟屏、无障碍与 shell 助手;网页能力使用 WebView 与 DevTools。两条链最终都把观察交回任务循环。依据仓库架构文档自制。
两条链的共同点是“观察、操作、再观察”。例如一次点击完成后,工具结果会附上动作效果和新的界面状态。模型可以据此改计划,而不是仅凭“点击函数返回成功”就推断目标已经完成。手机和网页还共用元素编号过期检测、界面稳定等待和部分无效果判断。
长任务怎样控制上下文,又怎样复用经验
模型每执行一步都要带上必要的历史。如果把所有截图、网页和工具结果原样累积,请求会不断变长。Mika 把上下文分为固定的系统提示词与工具定义、任务开始时的信息、只追加的历史,以及当前步骤的界面与运行状态。接近模型窗口时才压缩历史,当前任务的用户原话保留。这样既保留当前决策所需的信息,也尽量让重复发送的前缀保持稳定。
过去对话也没有无限塞进开局上下文。系统只带最近几轮的结局;需要更早的细节时,模型使用 history_read 从本对话的运行记录按页取回。网页、文件等外来文字会标记为不可信内容,避免把页面里的指令当作系统要求。这些都是上下文构造的规则,不意味着模型对外来内容绝不会误判。
对于重复任务,Mika 提供两种复用方式。App 或网站知识是预先写好的操作说明,模型按需查阅;手机上的成功路线可以记录为一串带锚点的动作,下次遇到相似任务先尝试回放,每步做轻量核对,失配就交回模型。项目当前不把网页任务纳入经验回放,因为动态页面和登录态差异更容易导致对位失败。
插话、等待和恢复怎样避免误操作
任务运行中,用户追加“先别发送,只总结”不会自动开第二个任务。这句话进入 RunInbox。如果模型请求还在等待,循环取消这次请求,把插话接到已有历史之后重问。已经开始执行的动作则会做完并记录,再在下一轮读取插话;这样不会出现动作执行了一半、记录却丢失的情况。
纯等待、按条件等页面、两次对外动作之间的间隔等,可以被新消息提前结束。do_steps 在两步之间看见插话,也会跳过尚未执行的步骤。结束任务时,收件箱与收尾在同一把锁下检查,避免最后一刻来的消息被误当作已经处理。
Mika 还把运行状态和结果送达分别落盘。进程被杀后,它不会从某个点击继续执行,因为当时的屏幕状态未必能恢复;它会把任务标记为中断,告知用户重新发起。已经写好但未送达的回复可以补送;送达状态不确定的回复不自动重发,以免重复通知或重复解释。
“安全”具体落在哪些代码里
ActionExecutor 的顺序是:先过操作守卫和锁屏关卡,再判定不可逆动作及同意情况,随后执行、核对结果、写运行记录。这个入口同时接收模型单步操作、do_steps 子步骤、脚本内动作和经验路线回放。其目的不是保证模型永远判断正确,而是把可检查的规则集中在同一位置。
但不能把“有执行入口”理解成“所有有风险的动作都会问用户”。当前默认的询问模式主要在花钱的下单步骤前要求确认;发送消息、发帖、提交和删除等动作可以直接执行。真正的付款步骤交给用户亲手完成。开发者选项中的自主模式更宽松,连花钱前的确认也不拦。来自电脑、定时任务等无法在手机上当场确认的运行,询问模式下遇到这类步骤会被拒绝。
另一个边界是结果核查。项目有证据账本、回答来源和独立核查代码,但开发文档明确写着最终回答核查当前被关闭,回答按“未核实”处理。后台的完成度分类仍会运行,成功路线和个人技能的学习主要依赖这个结局判定。它能减少重复操作,但不等于每个回答都通过了事实核验。
隐私也需要准确表述。Mika 默认直接连接用户配置的模型服务商,不依赖项目运营的中转服务;另有可选的自托管远程网关。本地保存会话、运行记录和加密后的密钥。但使用在线模型时,模型服务商仍会收到请求所需的文字或画面。沙箱里的 Python、Node 和 shell 默认断网,用户打开联网开关后才允许脚本访问网络。这些是不同层面的边界,不能合成一句“数据永不离开手机”。
这套实现的代价
虚拟屏能避免抢占主屏,但它依赖设备对虚拟显示、焦点和无线调试的支持。项目推荐安卓 14 及以上;不同厂商系统上的行为仍可能有差异。需要登录、验证码、支付的页面也仍要人接手。
界面自动化本身有不稳定性:按钮文字、控件树、页面结构、登录态与风控提示都可能变化。Mika 用操作后读回、条件等待、异常停止、App 与网站知识、成功路线回放来降低这种不稳定性,却不能把它变成确定性的接口调用。仓库路线图也把更多真机任务验证列为后续工作。
Mika 的实现可以概括为三层:TaskCenter 管任务,AgentLoop 管模型与观察的往返,手机、网页和沙箱能力负责实际操作。最有代表性的设计是把每次写操作收束到 ActionExecutor,并让独立虚拟屏承载手机 App。理解这两点,就能看清它为什么能在后台办事,也能看清它何时仍需要用户检查结果。















































































