这篇文章最初是一份实践前的理论整理。后续真机验证已经完成,部分结论发生了变化,尤其是“Shizuku 能让非 root 手机的 ADB 端口重启后保持开启”这一点,实测不成立。相关修正见文末和实践篇。
问题从哪里来
我希望让运行在 NAS 上的 AI Agent 调用手机上的一些能力,例如设置闹钟、查看 App 内容、读取通知,甚至完成一些日常操作。
直接调用手机厂商的端侧 AI 看起来最自然,但小爱、Siri、小艺等系统通常不会把完整的调用接口开放给第三方。于是问题变成:跳过端侧 AI,让 Agent 直接接触手机的系统能力。
NAS 上的 Agent
│ 自定义工具 / MCP / HTTP / ADB
▼
手机桥接层
│
▼
Android 系统能力:闹钟、日历、通知、App 界面
Agent 负责理解“我要做什么”,手机侧负责执行“系统允许做什么”。中间的桥接层决定了权限、稳定性和开发成本。
三条路线
| 方案 | 手机端要求 | 优点 | 局限 |
|---|---|---|---|
| 原生 HTTP/MCP 桥接 | 自建 Android App,前台服务 | 接口清晰,权限可控,适合长期运行 | 需要开发、安装和维护 |
| ADB + Tailscale | 开启调试并保持 adbd 可连接 | 灵活,能读 UI、模拟点击,验证速度快 | 权限边界、网络和重启状态都要自己处理 |
| Termux 轻量桥接 | 安装 Termux,运行脚本 | Python 即可验证,不必写原生 App | shell 权限有限,长期保活和系统能力不足 |
我的实际选择是:先用 ADB 验证需求,再决定哪些能力值得做成正式桥接服务。 如果连需求本身都没有跑通,直接写 App 很容易变成开发一个没人用的接口。
路线一:原生 HTTP/MCP 桥接
Android App 可以用 Kotlin 配合 Ktor 或 NanoHTTPD 提供本地 HTTP 服务,再把接口注册到 Agent 或 MCP 客户端。
比较适合做成接口的能力包括:
POST /alarm:创建一次性提醒或应用内闹钟;POST /calendar:写入系统日历;/notification:发送本地通知;- 音量、亮度、媒体控制等明确的系统操作。
后台运行通常需要前台服务和常驻通知。精确闹钟、日历写入、通知使用权等权限也要在首次使用时明确申请。
这里要分清“应用内闹钟”和“系统时钟里的闹钟”:AlarmManager 可以让自己的 App 在指定时间收到广播,但未必会出现在系统时钟 App 的列表里。若使用 ACTION_SET_ALARM,系统可能只负责预填页面,仍需要用户确认。不同厂商 ROM 的行为不能一概而论,必须真机验证。
安全上,服务只应监听必要的网卡和端口,并加 Token 认证;不要因为家里有 NAS,就把一个能控制手机的 HTTP 接口直接暴露到公网。
路线二:ADB + Tailscale
ADB 适合验证和探索,因为它不要求先开发一套 App。通过 Tailscale,可以让 NAS 和手机处在同一条虚拟网络里,手机即使换了 WiFi 或使用移动数据,也能通过固定的 100.x 地址被找到。
基本过程是:
- USB 连接手机,开启 USB 调试;
- 执行
adb tcpip 5555,让 adbd 暂时监听 TCP 端口; - 手机和 NAS 登录同一个 Tailscale 网络;
- 在 NAS 上执行
adb connect <手机 Tailscale IP>:5555; - 首次连接时在手机上确认 RSA 授权。
它的强项不只是执行 shell 命令,还包括读取 UI 树、模拟点击、启动 App 和抓取页面内容。平板自动查电费、主力机查快递,都是沿着这条路线做出来的。
实践后必须修正的一点
理论整理时,我曾经认为非 root 手机可以借助 Shizuku 写入 persist.service.adb.tcp.port,让端口重启后保持开启。真机测试证明这条路不成立:
- shell 用户不能直接写入
persist.*属性; - Shizuku 提供的是 adb/shell 级能力,不等于 root;
- 手机重启后,
adb tcpip 5555的状态会丢失。
因此,当前更可靠的办法是:接受端口可能变化,在 NAS 侧自动发现无线调试端口并重连。这样不用额外安装 Tasker、Automate 或其他保活工具,虽然不如永久端口漂亮,但实际更省事。
路线三:Termux
不想写 Kotlin 时,可以在 Termux 里用 Python 起一个 HTTP 服务或 MCP Server。它适合快速验证:本地通知、简单回调、脚本执行都能先做起来。
但 Termux 仍然是 shell 用户,不能自然地获得系统时钟、日历、通知读取和无障碍等深层权限。它更像实验台,不一定适合承担长期运行的核心能力。
怎么选
可以用三个问题做判断:
- 只是想验证一个想法? 先用 ADB。
- 功能固定、需要长期稳定运行? 写原生桥接 App。
- 想快速拼一个小工具? 先试 Termux。
| 维度 | ADB | HTTP/MCP 桥接 |
|---|---|---|
| 开发成本 | 低 | 中到高 |
| 临时探索 | 很适合 | 不划算 |
| 长期稳定 | 依赖网络和 adbd 状态 | 更容易控制 |
| 功能范围 | 很宽,可读 UI、模拟操作 | 取决于实现的接口 |
| 安全边界 | 较粗,需要谨慎 | 可以按接口最小化权限 |
安全边界不能省
手机控制权比普通 API 敏感得多。至少要做到:
- 不把 ADB 或桥接服务暴露到公网;
- Tailscale 配置 ACL,只允许必要的设备访问;
- HTTP/MCP 接口使用 Token;
- 只开放真正需要的动作;
- 涉及短信、通知、无障碍和支付 App 时,默认需要人工确认。
尤其是“能模拟点击”不等于“应该自动点击一切”。技术上能做的事情,和适合交给 Agent 的事情,不是同一个范围。
结论
让 NAS 上的 AI 调用手机能力,关键不是把厂商端侧 AI 拆出来,而是搭一条清晰、可控的桥:
- ADB 适合先验证和处理复杂、临时的界面操作;
- 原生 HTTP/MCP 桥接适合沉淀稳定、可审计的常用能力;
- Termux 适合快速试验,但不宜高估它的系统权限和保活能力。
我现在的路线已经从“先设计完整桥接层”改成了“先用 ADB 把真实需求跑通,再把值得长期保留的部分抽成工具”。实践比理论更慢,也更容易推翻漂亮的假设,但它能告诉你什么真的能用。