开源测试工具 那天我对着一台手机发呆

VictorXu · 2026年09月18日 · 最后由 难以怀瑾 回复于 2026年09月18日 · 154 次阅读

一颗 30 块钱的 ESP32-S3,把自己伪装成蓝牙鼠标,跨平台控制 Android / iOS / 鸿蒙——BlueHIDFlow 开源方案


那天我对着一台不让调试的手机发呆

接到一个跨平台自动化巡检任务,手机摆上桌就傻眼了。

Android 这台 ADB 被组织策略锁死,开发者模式入口直接屏蔽;iOS 那台 WDA 死活装不进,证书签名一路报错。Appium、Airtest 一个都跑不起来,环境地狱再一次糊脸。

盯着屏幕发了二十分钟呆,桌上的蓝牙鼠标随手一晃,光标在手机屏幕上跑了一格——等等。

这台手机什么都不让我装,却愿意接受一只蓝牙鼠标的输入。

那一瞬间逻辑全通了。如果蓝牙鼠标不需要权限、不需要信任、不需要装驱动,那只要我能让一块开发板把自己伪装成蓝牙鼠标,剩下的事就是一道纯软件题。

后来这个想法变成了一个开源项目,叫 BlueHIDFlow


先说说每个自动化人都吃过的"权限墙"

做过移动端自动化的人都知道,技术本身不算难。Appium 生态成熟,ADB 功能强大,Airtest 也很方便。

真正让人难受的,是执行环境及其稳定性

想测 Android,ADB 必须开。每个厂商有自己的小动作——有要插 SIM 卡的,有要走二次验证的,有要在隐藏菜单点七下版本号的。

想测 iOS,光是把 WDA 装进设备就能劝退一半人,xcode、开发者账号、证书签名一样不能少。

想跑鸿蒙,hdc 又是另一套生态。

更要命的是合规场景。生产环境的设备不允许开 USB 调试,不允许信任陌生电脑,iOS 的信任弹窗压根没人去点。跨平台还得维护两套完全不同的 Driver——UIAutomator2 写的脚本搬不到 XCUITest 上去。

这些问题本质是同一个:所有现有方案,都要求对目标设备做某种修改或授权——装代理、开调试、信任电脑、改设置。一旦设备说"不",自动化就到此为止。

要打破这道墙,得换条思路:别让设备配合你,去找一种它本来就配合的东西。


藏在每个操作系统里的"作弊码":BLE HID

BLE HID 全称 Bluetooth Low Energy Human Interface Device,是蓝牙 SIG 定义的标准协议。你每天用的蓝牙键盘、蓝牙鼠标、蓝牙触控板,底层跑的都是它。

关键不在协议本身,而在所有主流操作系统都把 HID 协议栈直接做进了内核

平台 BLE HID 原生支持 需要装驱动/APP
Android
iOS
HarmonyOS
Windows
macOS
Linux

手机收到 BLE HID 信号后,直接在系统输入层处理。它分不出这是真鼠标还是假鼠标,也不在乎——对它来说,就是一只标准蓝牙外设。

不需要装 APP,不需要开发者模式,不需要 USB,不需要信任电脑——配对就能用。

这就是 BlueHIDFlow 实现零侵入的全部秘密。不是绕过限制,是利用系统本来就开放的能力。


整套方案是怎么搭起来的

BlueHIDFlow 跑在 ESP32-S3 上。这块板子带蓝牙 5.0、双核 240MHz、16MB Flash、8MB PSRAM,单价 30 块出头,散卡 25 块也能买到。

它做的事很简单:把自己注册成一个标准 BLE HID 设备(鼠标 + 键盘),目标手机配对后把它当普通蓝牙外设,接收点击、滑动、输入等操作。

上位机/脚本 ──MQTT/WebSocket/HTTP/串口──> ESP32-S3 ──BLE HID──> 目标设备
                                              │
                                         OV2640 等摄像头
                                              │
                                         视觉大模型(云端或本地模型)
  • 控制通道:当前用 MQTT(TLS 加密),架构通过 IMqttPublisher 接口解耦,WebSocket / HTTP / 串口都能接
  • 图片上传:通过 ICameraUploader 接口抽象,开发者可自定义上传实现(OSS / S3 / 本地等)
  • 硬件成本:ESP32-S3-N16R8 开发板,约 30 元
  • 开源协议:Apache 2.0


和 Appium、ADB 摆在一起比一比

维度 Appium / WDA ADB / Scrcpy BlueHIDFlow
手机需装 APP 是(WDA / Agent) 否,但需开 USB 调试
需开开发者模式
需 USB 连接 否(可 WiFi) 否(蓝牙)
需信任电脑 iOS 需要 Android 需要
跨平台 需分别适配 仅 Android 一套方案全平台
环境配置 复杂 中等 简单
对手机侵入性
安全合规 风险高 风险中 风险最低

需要先说清楚:BlueHIDFlow 不是"更好用的 Appium"。

Appium 能跑 adb shell dumpsys、能装卸应用、能拿系统日志,这些 BLE HID 都做不到。它专注的是人类级操作——点击、滑动、文字输入、媒体按键,正好覆盖大部分日常自动化场景。系统级操作的活儿继续交给 ADB,两者互补。

它真正解决的问题是:当目标设备不允许你做任何修改时,你依然可以对它做自动化。这是 Appium 触达不到的场景,也是这个项目存在的意义。


5 行代码控制一台手机

讲了这么多,看看实际怎么用。

// 点击屏幕 (500, 300)
{"action": "TAP", "params": {"x": 500, "y": 300}}

//  (500,1000) 滑到 (500,500)
{"action": "SWIPE", "params": {"from_x": 500, "from_y": 1000, "to_x": 500, "to_y": 500}}

// 输入文字
{"action": "INPUT", "params": {"text": "Hello BlueHIDFlow!"}}

// Home / Back
{"action": "HOME", "params": {}}
{"action": "BACK", "params": {}}

Python 这边:

import paho.mqtt.client as mqtt

client = mqtt.Client()
client.connect("your-broker.com", 8883)

client.publish("bluehidflow/command/YOUR_DEVICE_ID",
               '{"action":"TAP","params":{"x":500,"y":300}}')

配对蓝牙,发条 MQTT 消息,手机就动了。

没有 Driver 下载,没有环境配置,没有 USB 调试,没有 xcode。


怎么跑起来

想自己试试,照下面这套来,30 分钟内能从零跑通。

准备硬件

ESP32-S3-N16R8 开发板,约 30 元。可选 OV2640 摄像头模块——直接买自带摄像头的开发版,别问为什么,外接摄像头的接线太痛苦。

装工具链

项目用 PlatformIO 管理依赖和编译,pio 是它的命令行入口。

  • VSCode 用户:装 PlatformIO IDE 插件即可,自带 pio
  • 命令行党:pip install platformio 一行搞定(需要 Python 3.6+)

烧录固件

# 1. 拉代码
git clone git@github.com:antgroup/BlueHIDFlow.git
cd BlueHIDFlow

# 2. 复制配置模板,填上你的 WiFi / MQTT broker / TLS 证书
cp config.example.h include/config.h

# 3. 拉依赖(首跑会下载 ESP32 SDK 和各类库,稍等几分钟)
pio pkg install

# 4. 用 USB 把 ESP32-S3 接到电脑,编译 + 烧录
pio run --target upload

# 5.(可选)实时看串口日志,确认启动正常
pio device monitor

配网与配对

上电后开发板会开 AP 热点 BlueHIDFlow-config(密码:bluehidflow),连上后访问 http://192.168.8.1 配置 WiFi 和 MQTT。TLS 加密连接需要填写 CA 证书(PEM 格式),也可在 include/config.h 中通过 MQTT_CA_CERT 宏预设。配完手机蓝牙搜一下,跟连蓝牙鼠标没区别。


踩坑速查(首次烧录最容易卡的几个点)

报错/现象 大概率原因 怎么办
pio: command not found PlatformIO 没装,或 pip 安装路径没进 PATH pip install platformio;macOS/Linux 把 ~/.local/bin 加进 PATH,Windows 重启终端
Error: Please specify upload_port 系统没认到 ESP32-S3 的串口 macOS / Linux 装 CP210x 或 CH340 驱动;Windows 在设备管理器看 COM 口,确认换根能传数据的 USB-C 线(很多线只供电)
烧录卡在 Connecting......_____ ESP32-S3 没进下载模式 按住 BOOT 键再按一下 RST,松开 RST、再松 BOOT;少数板子需要烧录时全程按住 BOOT
Permission denied: '/dev/ttyUSB0' Linux 用户没有串口权限 sudo usermod -aG dialout $USER 然后重新登录
fatal error: xxx.h: No such file 依赖没拉全 进项目目录跑 pio pkg install,还不行就 rm -rf .pio 重来一次
烧录成功但手机搜不到蓝牙 include/config.h 没填 / BLE 模块没启动 串口跑 pio device monitor 看启动日志,确认 BLE 初始化那一行没报错
配对上了但点击没反应 默认进的是键盘模式,没切到鼠标 通过 MQTT 发一条 {"action":"SWITCH_MODE","params":{"mode":"mouse"}},或在 include/config.h 里把默认 HID 模式改成 mouse

90% 的首次烧录失败都能在这张表里对上号。还遇到其他问题,欢迎到仓库 Issue 区开贴,会尽快回。


深入一点:项目里几个磨了很久的细节

跑通了想看技术内核的,这一节为你准备。

1. 怎么在 Android 上做"绝对坐标"

Android 和 HarmonyOS 不支持 BLE Digitizer(绝对触控坐标),只认 Mouse HID(相对坐标)。发"向右移 100 个 HID 单位",实际移动多少像素,看的是系统的鼠标加速曲线——不同设备、不同速度,结果完全不一样。

自动化最忌讳这种不确定。

BlueHIDFlow 用了个土办法,叫 Home-to-Target(归零 - 移动)

  1. 归零:每次操作前,连发 40 次 move(-127, -127),20ms 间隔,把光标怼到屏幕左上角
  2. 像素换算hidDelta = pixelDelta / pixelsPerHidUnit(默认 2.5 像素/HID 单位)
  3. 慢速移动:用 moveTo(hidX, hidY, durationMs) 把光标慢慢挪到目标位置,移动时长跟距离成正比(2ms/HID 单位,最低 200ms)

核心洞察是这一句:Android 对快速鼠标移动有加速,对慢速移动保持线性响应。控制好移动速度,Mouse HID 也能跑出接近绝对坐标的精度。

不是什么高深的算法,但能用。

2. Pimpl 模式隔离库冲突

BLE 键盘和鼠标两个第三方库有枚举定义冲突,直接编译会撞车。

BlueHIDFlow 把它俩 Pimpl 进各自的 .cpp,对外只暴露抽象接口 IKeyboardImpl / IMouseImpl。主代码不知道也不在乎背后用的是哪家的库,将来想换实现,改一个文件的事。

3. 自注册命令架构

想加一个新命令?写一个 .cpp 就够了:

class CmdMyCommand : public ICommand {
public:
    String name() const override { return "MY_COMMAND"; }
    CommandResult execute(const CommandContext& ctx) override {
        // 你的逻辑
        return CommandResult::success();
    }
};
REGISTER_COMMAND(CmdMyCommand)  // 编译时自动注册,不用改其他文件

REGISTER_COMMAND 宏在编译期把命令挂到 CommandRegistry 单例上。新增命令不用改注册表、不用动头文件、不用碰核心代码。HID 模式和配置项用的是同一套模式。

对开源项目来说,这个设计有个好处:贡献者只要管自己加的功能,不需要理解整个系统。降低 PR 门槛。

4. 模块按优先级初始化

Config(0) → Log(10) → LED(20) → Connection(30) → BLE(40) → MQTT(50) → Command(60) → WebServer(70)

每个模块实现 IModule 接口(setup / loop / end),按优先级顺序启动。不会出现"MQTT 还没连上就开始发命令"这种事。


下一步:让它自己看屏幕、自己决策

BLE HID 解决了"执行"的问题,但自动化只有"执行"是不够的。下一步要让它自己看、自己想、自己干。

OV2640 摄像头拍画面
        ↓
  视觉大模型理解屏幕(这是什么页面?该点哪?)
        ↓
  规划下一步(TAP 500, 300)
        ↓
  BLE HID 执行
        ↓
  再拍一次,验证结果
        ↓
  循环

执行层已经做完了——TAP、SWIPE、INPUT、HOME、BACK 都能用。摄像头模块(OV2640)也集成了 MJPEG 采集。AI Agent 的数据模型(ExecutionPlanVerificationResultTaskState)也都搭好了。

但有句话得说在前面:视觉理解这块,是真的难。

现在的视觉大模型,输入大多是手机截图,而 BlueHIDFlow 的摄像头拍到的是"人眼视角"的手机画面——畸变、反光、角度偏移、环境光全是干扰。那些专门用屏幕截图训练的模型,在这个场景下效果一般。

屏幕元素识别的准确率、操作规划的鲁棒性、多步任务的上下文维护、不同 App 界面的泛化能力——每一个单拎出来都是独立的题。当前的多模态大模型在静态截图理解上已经不错了,但实时性、准确率、成本三者怎么平衡,还得慢慢磨。

这不是接个 API 就能跑起来的事。如果你对 AI Agent + 物理世界交互感兴趣,欢迎一起搞。


项目链接

这个项目最初只是为了搞定那台不让我插 USB 的手机。后来想了想,遇到这个问题的人应该不止我一个,干脆开源出来。

如果你也踩过移动端自动化的环境地狱,欢迎试试,欢迎 Star,欢迎 Issue 和 PR。

让移动端自动化不再需要改手机。

共收到 1 条回复 时间 点赞
回复内容未通过审核,暂不显示
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册