
手里有十几台手机想让它们同时跑同一个程序一台电脑全管住——这个需求听起来像个软件问题真正动手才会发现卡点根本不在软件上。我第一次搭多机位的时候十台机器一字摆开Hub 插上电脑只认出来四台剩下六台在黑屏充电屏幕上连个授权弹窗都没有。折腾了大半夜才明白问题出在供电和 USB 拓扑而不是任何一款控制工具。这篇东西就是把这套流程从零到跑通讲清楚一台电脑怎么同时操控多部手机、让它们并行运行程序从硬件连接层、ADB 底座、投屏可视化一直到脚本化自动执行和踩坑排查。内容偏向实操适合做 App 兼容性验证、多设备回归测试、直播中控、电商后台多店铺管理的同学参考也适合完全没接触过 ADB、只会用鼠标点手机的新手照着抄。我不会只给你一串命令每一步为什么这么做、不这么做会出什么问题都会讲透——因为多机场景里90% 的失败都不是命令写错而是环境和硬件没打牢。1. 先分清你要的是看得见还是点得动很多人一上来就问哪个软件能群控手机这个问题本身就没问对。多机协同其实是由两个可以完全拆开的能力拼起来的一个是把手机屏幕搬到电脑上让你看见镜像投屏一个是把电脑上的操作送到手机上让它执行指令下发。这两件事可以用完全不同的工具做也可以合并到一套商业软件里做但你先得知道自己要哪个。1.1 四种典型场景与对应的技术路线我把常见的需求归成四类你可以直接对号入座。这个分类决定了后面所有选型选错了会白折腾很久。场景核心诉求推荐路线单机稳定带机量经验值演示、远程查看、录屏留档画面同步scrcpy 多窗口镜像8 到 12 台人工多开操作直播中控、多店铺后台画面 键鼠映射投屏 一套键鼠广播到多台6 到 10 台批量跑程序、回归测试程序自动执行ADB uiautomator2 / Appium20 台以上受 USB 拓扑限制规模化跑量几十到上百台稳定、可调度、可回收真机集群或云端真机按机柜/按需1.2 为什么看得见和点得动要分开考虑投屏这类工具比如 scrcpy本质是把手机的 H.264 视频流通过 ADB 通道拉到电脑上解码显示它只负责看。而指令下发走的是另一条路adb shell input tap 500 1200这种命令直接调用系统的输入子系统跟你在屏幕上用手指戳是一样的效果。两者互不依赖。分开考虑的好处是当你要做自动化时完全不需要开投屏省掉大量带宽和 CPU当你要人工操作时也不需要写任何脚本。很多新手一开始就去找一体化群控软件结果被授权、绑定设备数量、版本升级这些问题卡住其实用两个免费工具拼起来就能覆盖大部分场景。提示如果你所在的环境对软件来源有要求优先选开源命令行工具可审计、可脚本化出问题也容易定位到具体哪一层。2. 让电脑真正看见十台手机供电、拓扑、驱动三关这一节是全文最容易被跳过、也最容易翻车的部分。我可以很负责任地说多机场景里最常见的故障不是工具挂了而是手机根本没被电脑正确识别或者识别了但反复掉线。2.1 USB Hub 选型独立供电不是可选项手机插在电脑上除了通信还要充电。绝大多数手机在 USB 连接状态下充电电流起步就是 5V/1A部分机型会尝试协商更高。主板上的 USB 口通常一个口只能提供 900mAUSB 3.0 标准是 900mAUSB 2.0 是 500mA你插三台就超了。超了会怎样不是立刻断电而是电压被拉低表现为设备反复重新枚举、ADB 连接时断时续、手机屏幕亮一下又黑。这种软故障最难查因为它不是稳定复现的。所以选 Hub 的标准很明确必须带独立电源适配器标称输出至少覆盖所有端口的总电流。10 台手机按每台 1A 算就是 10A 5V实际买不到这种规格的话用 12V/5A 输出的工业 Hub约 60W基本够用因为大多数手机在 USB 数据模式下充电电流会降到 500mA 左右。优先选带过流保护和独立开关的工业级 Hub不是那种几十块的消费级分线器。多机位要长时间通电消费级 Hub 的电源模块很容易热衰减。接口带宽要匹配。USB 2.0 理论 480Mbps、实测共享约 280MbpsUSB 3.0 是 5Gbps。如果你只插 4 台以内USB 2.0 也能跑上到 8 台以上做投屏就明显挤了。2.2 驱动与 ADB 环境的最低可用配置Windows 上绝大多数安卓手机需要装厂商 USB 驱动或者用 Google 的通用 USB 驱动。Linux 和 macOS 基本免驱但 Linux 需要配 udev 规则否则普通用户没有权限访问设备节点会出现no permissions。ADB 本身来自 platform-tools 包把它解压到任意目录加进 PATH 就行。这里有个细节不要让多个版本的 adb 同时存在于系统里。adb 是一个 C/S 结构client 和 server 版本不一致时会互相踢掉对方表现为设备列表突然清空。我遇到过好几次设备莫名其秒消失最后发现是某个 IDE 自带了一份旧版 adb后台把 server 重启了。统一版本的做法adb kill-server adb start-server adb version三台设备以上时建议先adb kill-server再start-server让 server 用同一份二进制重新枚举。2.3 设备识别不稳的四种典型症状与对应原因症状大概率原因处理方向插上只充电不弹授权弹窗数据线只有充电线芯或 USB 口只供电换线优先原装或带数据传输认证的线授权弹窗点了允许仍然 unauthorized弹窗被系统拦截或未勾选始终允许撤销 USB 调试授权后重插勾选始终允许设备反复 offline供电不足、线材接触不良、Hub 带宽争抢单独给 Hub 加电换短一点的线每次重新插拔设备 ID 都变无线调试或某些 ROM 的序列号隐藏用adb devices -l看完整信息或统一用有线3. ADB 是所有多机方案的底座用 -s 把命令精确投送到指定设备不管你最后用哪套工具底层几乎都绕不开 ADB。理解了 ADB 在多机下的工作方式你就能自己拼出任何想要的功能。3.1 adb devices 的输出怎么读adb devices会列出所有已连接设备格式是序列号 状态。状态只有几种含义差别很大device正常可以下发命令。offline设备在列表里但连不上通常是连接不稳定或者系统还没启动完。unauthorized手机上没点授权或者授权被撤销了。no permissionsLinux 下的权限问题需要 udev 规则。多机场景下你需要的是序列号 → 设备的映射。序列号是每台设备的唯一标识命令里用-s指定adb -s 1A2B3C4D shell input keyevent KEYCODE_WAKEUP如果不加-sadb 在只有一台设备时能正常工作一旦有多台就会直接报错more than one device。所以从第一行脚本开始就养成处处带 -s 的习惯这个习惯能帮你省掉后面无数的诡异问题。3.2 用 shell 脚本批量下发指令把设备列表取出来做循环是最简单可靠的批量方式#!/usr/bin/env bash # 唤醒所有设备屏幕并回到桌面 for s in $(adb devices | awk $2device{print $1}); do adb -s $s shell input keyevent KEYCODE_WAKEUP adb -s $s shell input keyevent KEYCODE_HOME done这里用awk $2device过滤是为了把 offline 和 unauthorized 的设备排除掉否则整个循环会卡在报错上。批量脚本一定要做这种防御否则一台设备出问题会拖垮整批任务。如果是更复杂的操作比如同时安装一个 APKfor s in $(adb devices | awk $2device{print $1}); do adb -s $s install -r -d app-release.apk done wait结尾的加wait是并行执行的关键。串行装 10 台 APK 可能要几分钟并行能压到几十秒。但要注意并行安装会同时占用 USB 带宽如果设备多、APK 大反而可能变慢甚至超时一般建议并行度控制在 4 到 6。3.3 免 root 状态下能做什么、不能做什么大多数人的设备不会 root好消息是常用操作基本够用能做的input tap/swipe/text/keyevent模拟点击、滑动、输入、按键、screencap截屏、screenrecord录屏、pm install/uninstall/clear装包、卸载、清数据、am start启动 Activity、dumpsys读系统状态、pull/push传文件。受限制的修改部分系统设置、模拟某些需要系统权限的点击、读取其他应用私有目录。这类操作在部分国产 ROM 上需要额外开启USB 调试安全设置之类的选项而且往往要求登录厂商账号、插入 SIM 卡。这是系统层面的限制不是你脚本写错了。提示如果你的自动化脚本在真机上点了没反应但手动点可以第一个要排查的就是这个安全设置级别的调试开关而不是怀疑坐标算错了。4. 把十块屏幕搬到桌面上scrcpy 多窗口的实操配置投屏这块我个人一直用 scrcpy原因很简单开源、走 ADB 通道不需要装手机端 App、延迟低、支持命令行参数批量启动非常适合多机。4.1 单机验证到多机批量启动先在单台设备上跑通确认能出画面scrcpy --serial1A2B3C4D --max-size1024 --max-fps30单机能出画面说明 ADB 通道和视频解码都没问题。接下来做多机批量核心思路是每台设备起一个独立进程用参数把窗口排好位置避免十块窗口叠在一起#!/usr/bin/env bash i0 for s in $(adb devices | awk $2device{print $1}); do i$((i1)) col$(( (i-1) % 4 )) row$(( (i-1) / 4 )) scrcpy --serial$s \ --window-titledev-$i-$s \ --window-x$(( col * 470 )) \ --window-y$(( row * 880 )) \ --window-width460 --window-height860 \ --max-size800 --max-fps15 --video-bit-rate2M \ --no-audio --stay-awake --turn-screen-off sleep 0.5 done这段脚本做了几件事按 4 列排布窗口、给每个窗口起带编号和序列号的标题方便定位是哪台、压低分辨率和码率、关掉音频、保持屏幕常亮、把手机物理屏幕关掉省电。最后的sleep 0.5是给 ADB 一点喘息时间避免十个进程同时抢连接。4.2 参数取舍多机场景下该压什么、不该压什么多机投屏的性能瓶颈主要在三处USB 带宽、电脑 GPU 解码能力、手机端编码负载。参数调优就是在这三者之间找平衡。参数作用单机建议10 台场景建议--max-size限制长边分辨率1920720 到 800--max-fps限制帧率6010 到 15--video-bit-rate码率8M1M 到 2M--no-audio禁用音频转发视需要建议禁用--turn-screen-off关闭手机物理屏无所谓建议开启--stay-awake保持唤醒无所谓建议开启算一下带宽就明白为什么要压默认 8Mbps 的码率10 台就是 80Mbps挂在 USB 2.0 的共享 280Mbps 上表面看还行但 ADB 指令、截图、文件传输都在同一条通道上挤稍微一忙就卡。压到 2Mbps 后总量 20Mbps留出了充足余量。4.3 一套键鼠操作多台时的冲突处理scrcpy 默认把键盘鼠标输入转发给对应窗口所以每个窗口是独立的鼠标点到哪个窗口就操作哪台。如果你想让一次点击同时作用到所有设备scrcpy 本身不提供这个能力需要走 ADB 广播路线用第 3 节那种循环脚本把同一个坐标发给所有设备。这两种模式对应两种真实需求独立操作适合逐台检查、逐台处理异常广播操作适合批量执行同样的动作。我一般把投屏当监控 手动兜底把 ADB 脚本当主力执行两者配合使用效率最高。5. 从手动点升级到自动跑脚本化并行执行的三条路线当你需要多部手机同时运行程序、并且不需要人盯着的时候就得从投屏切到自动化脚本。这里有三条由浅入深的路。5.1 路线一ADB input 直接模拟最快上手优点是不用装任何东西缺点是坐标必须硬编码屏幕分辨率一变就废。适合固定机型、固定分辨率、界面稳定的场景。adb -s $s shell input tap 540 1600 sleep 1 adb -s $s shell input swipe 540 1800 540 900 300input swipe的最后一个参数是滑动时长毫秒不要设太短太短会被系统识别成 fling 而不是滑动很多列表滚动会滑过头。5.2 路线二uiautomator2 / Appium能按元素定位这是自动化测试的正规玩法。uiautomator2 相对轻量Python 侧写起来也顺手import uiautomator2 as u2 from concurrent.futures import ThreadPoolExecutor SERIALS [1A2B3C4D, 5E6F7G8H, 9I0J1K2L] def run_one(serial): d u2.connect(serial) d.app_start(com.example.app) d(text开始).click() d.swipe_ext(up, scale0.6) with ThreadPoolExecutor(max_workers4) as pool: pool.map(run_one, SERIALS)关键点是max_workers控制并发度。我实测下来一台普通办公电脑跑 4 到 6 个并发比较稳超过之后每个任务的响应时间会明显拉长反而总耗时更长。5.3 路线三设备池 任务队列 失败重试设备一多就必须把设备当资源管理。基本做法是维护一个设备状态表分为空闲、占用、异常三个状态。任务从队列取取任务时先分配一台空闲设备跑完释放跑失败就标记异常并把任务重新入队。几个实战细节心跳检测每隔 30 秒用adb -s $s shell getprop sys.boot_completed探一下返回 1 说明设备活着否则从池里摘掉。失败重试要限次数一般 2 次。有些失败是环境性的网络抖动、界面加载慢重试能救有些是逻辑性的重试一百次也没用还浪费时间。每台设备跑完自动清理数据用pm clear回到干净状态避免上一轮残留影响下一轮。6. 多机跑起来之后的坑从掉设备到带宽打满前面讲的都是应该怎么做这一节讲实际会怎么坏。我把最典型的几个坑和完整排查链路写出来你可以直接照着复现排查思路。6.1 一次完整的排查为什么第 7 台设备总是掉这是我早期遇到的一个非常典型的案例。10 台设备接在一个 Hub 上前 6 台稳定第 7 台开始每隔几分钟掉线一次重插就好过一会又掉。我的排查顺序是这样的换线换口。把第 7 台的线换到第 3 台的口上结果第 3 台开始掉第 7 台稳了。这一步说明问题跟着**物理位置端口**走不跟着设备走基本锁定是连接层问题不是手机本身的问题。单独测试。只留第 7 台设备在 Hub 上稳定运行半小时没问题。说明这根口本身不是坏的是设备多了之后才出问题。怀疑供电。摸了摸 Hub外壳明显发烫。查看了 Hub 的电源适配器规格是 5V/2A也就是总共只有 10W 输出能力。10 台手机哪怕每台 500mA也要 5A早就超了。而前 6 台之所以稳是因为它们排在前面抢到了电流。验证结论。给 Hub 换上 12V/5A 的适配器第 7 台再也没掉过。整个过程里我一次都没改过软件配置问题完全在硬件。这就是为什么我在第 2 节花那么多篇幅讲供电——在多机场景里先排查物理层再排查软件层顺序反了会浪费大量时间。6.2 带宽和功耗的量化估算方法与其拍脑袋不如算一下。带宽方面单台投屏码率 × 设备数再叠加指令和截图的占用总和不能超过通道实测带宽的 70%。USB 2.0 按 280Mbps 算10 台各 2Mbps 码率占 20Mbps加上其他开销也就 30Mbps 左右很宽松但如果你用默认 8Mbps10 台就是 80Mbps再叠上频繁截图就危险了。功耗方面单台 USB 数据模式下充电电流取 500mA10 台就是 5A 5V 等于 25W。加上 Hub 自身损耗和冗余电源适配器至少按 1.5 倍配也就是 40W 起步稳妥点直接上 60W。6.3 日志和截图留证别靠记忆多机场景出了问题事后最痛苦的是记不清是哪台、什么时候、什么现象。我现在的习惯是每次批量执行都开一份日志用adb -s $s logcat -s TAG:* logs/$s.log 按设备分别落盘。关键节点自动截屏adb -s $s exec-out screencap -p shots/$s-$(date %s).png文件名带时间戳。投屏时加--recordrec/$s.mp4需要复盘的场景直接看录像。这三样东西加起来占不了多少磁盘但能把排查时间从半天压到十分钟。7. 自建真机墙还是用云端成本账与几条底线最后聊聊规模化之后的取舍以及必须守住的边界。7.1 自建和云端的账怎么算维度自建真机墙云端真机初期投入手机 Hub 机架 电脑笔数不小基本为零单机成本一次性长期摊薄按小时或按次计费稳定性取决于你的供电和线材需要维护平台负责但受网络影响机型覆盖只能覆盖你买的机型机型池大可以做兼容性矩阵数据可控性完全在自己手里依赖平台适合场景长期、固定机型、高频使用短期、多机型、低频验证我的判断标准很简单如果同一个机型你每天都要跑自建更划算如果只是偶尔验证某个新机型的兼容性云端更省心。两者也不是互斥的常见做法是自建几台主力机型做日常回归遇到机型矩阵测试再上云端补位。7.2 几条必须守住的底线技术是中性的用途决定了它的性质。这套多机方案适合用在自有设备上做自己应用的测试、验证、多店铺后台管理等正当场景。几个原则只操作自己拥有或明确获得授权的设备不要触碰他人设备。只使用自己的账号不要做批量注册、虚假流量、刷单等违反平台规则和应用服务条款的行为。自动化脚本的规模和频率要控制在合理范围内避免对目标服务造成异常压力。遵守所在环境和目标应用的各项规定不确定是否合规的场景宁可不用。这些年我在多机项目上踩过的最大一个坑其实不是技术而是贪多。一开始总想着一台电脑带二十台结果就是不断出问题、不断救火。后来我把策略改成单组 6 台、多组并行、每组独立供电稳定性一下子上来了。设备数量不是目标稳定跑完任务才是。还有一个特别小的技巧分享给你用不同颜色的线或者贴标签把每台设备对应到固定端口出问题时你只需要看颜色就能定位是哪一路比对着序列号找半天高效得多。