☰
Open-AutoGLM+ADB键盘:Android设备自动化实战与踩坑指南
2026/10/8 15:38:14 网站建设 项目流程

很多刚接触Android自动化的朋友,第一反应是去研究无障碍服务,或者装一个“按键精灵”类的录屏回放工具。我最近几个项目里反而一直在用Open-AutoGLM来做Android设备上的自动操作,底层执行统一走ADB,输入文字用ADB键盘控制,这套组合跑了几周,稳定性比我想象中好不少。如果你也想让自己的Android设备自动完成签到、打卡、批量操作演示,或者做一台24小时无人值守的测试机,这篇文章就是我这次实战的完整复盘,包括环境搭建、ADB键盘配置、自动化任务落地,以及几个不太容易搜到答案的坑。

1. Open-AutoGLM到底在解决什么问题:把“手机自动化”从脚本升级成“看得懂的自动化”

1.1 先拆解一下这套组合里的三个角色

Open-AutoGLM从名字上看,是一个把大模型理解能力对接到Android设备操作上的开源自动化框架。它和传统“坐标点击脚本”最大的区别在于:脚本是死记硬背的,屏幕上按钮位置一变化就废;而Open-AutoGLM是“看”屏幕内容的,它先拿到当前界面的信息,理解任务目标,再决定下一步点哪里、输入什么、要不要滑动返回。

在我实际使用的这个版本里,整套体系的角色分工非常清晰:

  • 感知层:负责看。通过ADB截图和UI层级导出,拿到“屏幕上现在有什么”;
  • 决策层:负责想。把截图和任务描述一起交给多模态模型,模型输出类似“点击界面中央的签到按钮”的动作;
  • 执行层:负责动手。把模型输出的动作翻译成一条条ADB命令,包括模拟点击、滑动、按键,以及调用ADB键盘完成文字输入。

所以你看到的实际效果是:手机像有了个“遥控手”,并且这个手长了个会分析界面的大脑。传统脚本是“如果坐标等于(500, 1200)就点击”,Open-AutoGLM是“检测到页面顶部有一个写着签到的按钮,那就点它”。后者明显更适合真实设备环境,因为真实App里每个界面的元素位置都会因为屏幕尺寸、分辨率、系统导航方式而变。

1.2 和其他自动化方案的横向对比

为了把Open-AutoGLM这套组合放在合适的位置,我当时特意把主流方案都列了一下:

方案识别方式稳定性权限要求适合场景
无障碍服务读取界面节点中,经常受App定制控件影响需要开启无障碍服务单机轻度自动化
坐标点击脚本写死像素坐标低,换机型或换分辨率就废几乎无录屏回放、临时演示
Appium等测试框架通过UiAutomator/XCUITest驱动高,但配置重需要调试授权自动化测试团队
Open-AutoGLM + ADB图像+UI层级+模型决策高,且能适应界面变化ADB授权 + 输入法切换无人值守的智能操作

这里不是说无障碍服务没有价值,而是它在应对复杂弹窗、界面改版、以及需要输入中文的场景时,容易因为“拿不到目标控件”而中断。Open-AutoGLM和ADB的组合把“看”和“做”拆开了,感知可以选截图、选UI层级,实在不行还能做模板匹配;执行则全部落到ADB这一条稳定的通道上,不用管App内部怎么实现控件。

1.3 为什么最终选择了ADB作为执行通道

开发者选项里的ADB通道,本质上是Android系统在系统级提供给外部调试、控制的接口。它的优势在于“权限层级高”:很多无障碍服务碰不到的输入框、被App自定义View拦截的点击事件,ADB通过input命令和输入法广播都能触达。另一个关键点是,ADB不依赖某个App进程,即使目标App崩溃或页面卡死,ADB通道还活着,你可以继续发送返回键、杀掉进程、重启App。

这一点对于自动化来说太重要了。我见过太多脚本因为目标App白屏、弹窗遮挡就把整套流程卡死,最后只能人工介入。换成ADB做执行层之后,至少你有能力在每一轮操作前后做“体检”,发现不对就按返回键、关掉弹窗、重新拉起目标页面。这也是我后来把所有自动化任务都收敛到Open-AutoGLM + ADB这套架构上的根本原因。

2. 环境搭建:ADB安装、连接授权与两种远程调试方式

2.1 ADB的安装:不同平台的区别和常见坑

ADB本身不用编译,直接用官方Platform Tools就行。macOS用户最省事的方式是:

brew install android-platform-tools

Windows用户一般从Android开发者官网下载Platform Tools压缩包,解压后把platform-tools目录加进PATH。这里有个很常见的坑:解压完直接打开cmd输入adb,提示“不是内部或外部命令”,就是因为没加环境变量。另外Windows下还需要装好对应手机品牌的USB驱动,否则设备管理器里只会显示一个带黄色感叹号的“Android Composite ADB Interface”。

Linux用户需要注意发行版差异:

sudo apt install android-tools-adb # Ubuntu/Debian sudo pacman -S android-tools # Arch

装完以后用adb version确认即可。紧接着把手机开发者选项里的“USB调试”打开,插上数据线,第一次会弹出RSA密钥确认框,勾选“始终允许使用这台计算机进行调试”,然后保持手机亮屏。

我实际测试中还遇到过一种情况:有些朋友手机连电脑出现device offline,反复拔插也不行。这种时候一个通用咒语是:

adb kill-server adb start-server adb devices

ADB服务端偶尔会进入一种“以为设备还在但设备已经断开”的状态,杀掉重启通常能恢复正常。还有一种情况是电脑上跑着某些手机助手类软件占用了ADB端口,也会导致设备识别异常,建议做自动化之前把这些软件全部退掉。

2.2 连接授权不通过:unauthorized状态的完整排查

热搜词里“adb unauthorized怎么解决”出现频率很高,这确实是新手最容易卡住的一环。当你执行adb devices看到这行输出:

List of devices attached XXXXXXXXXXX unauthorized

完整的排查链路应该是这样的:

  1. 先看手机屏幕上有没有弹RSA授权框。如果弹了但点了拒绝,后续就不会再弹。解决方法是到“开发者选项”里点“撤销USB调试授权”,然后拔线重插,重新弹窗授权;
  2. 如果屏幕上没弹窗,检查是否勾选了“始终允许使用这台计算机进行调试”,没勾选的话授权框只弹一次,取消后就看不到;
  3. 部分国产定制系统(我手上遇到的就有MIUI、ColorOS系)在“USB调试”之外还单独有一个“USB安装”或“USB调试(安全设置)”选项,不打开的话连接是unauthorized或offline,这一步经常被忽略;
  4. 最后再考虑ADB服务端问题,执行一次adb kill-server后重新连接。

顺便做一张表帮大家对照常见的连接状态含义,排查时一眼就能定位:

adb devices输出含义常见处理
device正常连接,可执行命令无
unauthorized手机端未授权这台电脑重新弹窗授权
offline设备曾经连过但现在通信异常重插/重启adb server
no permissions多为Linux下udev规则问题配置/etc/udev/rules.d/51-android.rules或换root权限重试

排查这部分不要东一榔头西一棒子,按这个顺序走一遍,绝大多数unauthorized都能解决。我当时光是这个问题就在一台备用机上折腾了半小时,最后发现其实是系统UI隐藏了授权弹窗,直接进“撤销授权”再重插就搞定了。

2.3 无线调试与无电脑场景的替代方案

做Open-AutoGLM自动化任务时,我强烈建议用无线方式连接,不然测试过程中手机稍微动一下USB线,连接就断了,脚本全废。Android 11以上自带无线调试,操作路径是:

  1. 开发者选项里打开“无线调试”,点开详情记下配对用的IP和端口;
  2. 电脑上执行配对命令:
adb pair <ip:port> <配对码>
  1. 配对成功后,在“无线调试”界面看到已分配IP和端口,执行:
adb connect <ip:port>

之后只要手机和电脑在同一个局域网内,连接就一直保持。adbd本身会在后台运行,不用每次都插线。

那完全没有电脑的场景怎么办?我在折腾过程中试过一条路:手机网页连接ADB。像WebADB这类工具,可以在手机浏览器里直接打开一个页面,配合USB OTG转接线接到另一台Android设备,网页上就能跑ADB命令。这在来回路程中排查设备问题时很实用,尤其是Open-AutoGLM已经部署到目标手机上、手边没有PC的情况。另外还有“甲壳虫ADB助手”这类手机端App,可以图形化地管理已连接的设备,查看当前Activity、模拟点击、查看屏幕截图,相当于把ADB调试器搬进了手机。

如果你准备把自动化任务长时间跑下去,无线调试几乎是必选项。记住一个小细节:手机息屏后无线调试可能休眠,建议在开发者选项里保持“屏幕常亮”的条件充电,或者最低限度关掉自动锁屏。

3. ADB键盘控制:为什么需要它,以及如何正确配置

3.1 ADB原生输入命令的局限

ADB本身有一个文本输入命令:

adb shell input text "hello"

但这玩意的限制非常明显:只能输入英文字符和数字,中文、特殊符号基本无能为力。另一个更麻烦的问题是,input text把文本直接发给当前获得焦点的控件,如果目标App的输入框是自绘控件、或者页面还没完成加载,你会看到内容输进去了,却什么都没发生。

为什么ADB键盘能绕开这些问题?因为它的底层机制完全不一样:ADB Keyboard本质是一个输入法(IME),你把它设成当前输入法之后,App只知道自己调用了一个系统输入法来接收按键事件,并不知道背后是ADB在发指令。这个思路有点像“伪装成你的打字手指”——系统层面认可它是输入法,App层面看到的就是正常的键盘输入。所以无论是中文输入框、搜索栏,还是自绘控件里的输入区域,ADB键盘都能稳定地把字符逐个送进去。

3.2 ADB Keyboard的安装、启用与验证

ADB Keyboard的安装包在网上很容易找到,一般叫ADBKeyboard.apk或AdbIME.apk。安装过程非常简单:

adb install -r ADBKeyboard.apk

然后把它设为当前输入法:

adb shell ime enable com.android.adbkeyboard/.AdbIME adb shell ime set com.android.adbkeyboard/.AdbIME

ime enable是让系统认识这个输入法,ime set是真正把它切到前台。这里有个容易忽略的点:某些定制ROM会要求在“开发者选项”里打开“USB调试(安全设置)”或“模拟点击”相关权限,否则键盘虽然切换成功,但广播发过去没有效果。

配置完成后需要做一次实测。在目标App里点开一个输入框,然后电脑上执行:

adb shell am broadcast -a ADB_INPUT_TEXT --es msg "自动输入测试"

手机上如果立刻出现“自动输入测试”这几个字,说明链路已经通了。注意广播内容里的特殊字符,如果包含换行或双引号,建议先用ASCII码方式处理,或者退而求其次用ADB_INPUT_KEYCODE发送按键。实测下来中英文混输都没问题,个别设备上偶发字符丢失,重发一次就好。

3.3 从键盘输入到模拟按键:一条可直接复制的链路

ADB键盘不止能输入文字,还能模拟按键事件。先看一段我在项目里实际用过的最小链路:打开一个便签App,写入一条文字,然后返回桌面。把这套逻辑整理成shell脚本就是这样:

echo "启动便签App" adb shell am start -n com.example.notepad/.MainActivity sleep 2 echo "切换到ADB键盘,确保输入可用" adb shell ime set com.android.adbkeyboard/.AdbIME echo "输入文字" adb shell am broadcast -a ADB_INPUT_TEXT --es msg "Open-AutoGLM 自动测试记录" echo "稍等片刻,按Home返回桌面" sleep 1 adb shell input keyevent KEYCODE_HOME

这里am start -n后面的包名和Activity名要换成本机目标应用的。Activity名可以通过adb shell dumpsys package <包名> | grep -A 1 "android.intent.action.MAIN"查到,或者用adb shell monkey -p <包名> -c android.intent.category.LAUNCHER 1打开首页后执行adb shell dumpsys window | grep mCurrentFocus看当前焦点窗口。

这套链路虽然简单,但把ADB键盘、模拟按键、进程管理三个能力串起来了。后面Open-AutoGLM每执行一个动作,本质上就是在不断重复和组合这类原子操作:找元素、点按钮、输文字、返回到指定状态。

4. 让Open-AutoGLM真正跑起来:一次完成自动签到实战

4.1 任务拆解:从“签到”到可执行的步骤序列

我拿自动签到来举例,是因为它足够典型:要打开App、等待加载、定位按钮、点击、处理结果弹窗。如果这些步骤能稳定跑通,其他自动化任务基本都是同一套逻辑换个皮肤。

先把任务拆成以下步骤:

  1. 检查设备连接状态,确保ADB在线;
  2. 启动目标App,等待首页出现;
  3. 获取当前界面UI信息,定位“签到”按钮坐标;
  4. 执行点击;
  5. 检查是否出现签到成功或者弹窗,如果弹窗则关闭;
  6. 截图存档,记录任务结果。

这里要特别强调一点:不要用固定sleep来等待页面加载,尤其是网络不好的时候,固定等待不是等“出现”,而是在赌“一定够”。更可靠的做法是循环检测:每0.5秒截一次图或导出一次UI层级,直到目标元素出现再继续。Open-AutoGLM的循环决策机制正好能覆盖这一点,它会在每一步结束后重新感知当前界面,再决定下一步动作。

4.2 初始化Open-AutoGLM:模型接入、工具注册和权限准备

不同发行版的Open-AutoGLM可能会有配置文件差异,我这里给出的是我实际用下来比较顺的一套初始化思路。它通常需要配置设备、模型、工具集和任务目标四块:

device: "127.0.0.1:5555" # 无线调试地址,也可以直接写USB序列号 model: provider: "openai-compatible" model: "glm-4.5v" # 换成你实际可用的多模态模型 tools: - adb_tap - adb_keyboard_input - uiautomator_dump - screencap task: "打开社区App,找到签到按钮并完成签到,记录截图" timeout: 120

工具注册是这套体系里非常关键的抽象:每个能力对应一个工具函数,比如adb_tap接收一个坐标参数,执行adb shell input tap x y;adb_keyboard_input接收一段文本,发送ADB键盘广播。Open-AutoGLM要做的,就是根据模型决策在工具池里挑出合适的那个来调用。

启动的时候还有个权限准备步骤容易被忽略。第一是确认ADB授权状态,第二是确保ADB Keyboard已经是当前输入法,第三是允许目标App的必要权限(比如存储、悬浮窗),否则模型明明识别出了“允许”按钮,点下去却被系统权限页挡了一道。

4.3 运行与观测:用截图、日志和UI状态监视每一步

自动化跑起来之后,如果看不到过程,出了问题就只能从头再来。我在项目里养成了一个习惯:给每个步骤都留观测点。

日志观测最简单,直接过滤Open-AutoGLM的输出:

adb logcat -s OpenAutoGLM:D *:S

比纯看日志更有效的是截图证据链。Open-AutoGLM每执行一个动作,我就把当前屏幕截一张图存档,后续回溯是“模型看错了界面”还是“ADB命令没生效”,一眼就能分辨。这里一个小技巧是用exec-out替代shell screencap,输出更干净:

adb exec-out screencap -p > step_001.png

配合一个简单的循环,可以把整个自动化过程变成一组连续截图,相当于给任务录了个无声视频。真出问题的时候,按时间线翻截图比读一千行日志快得多。

4.4 失败恢复:脚本挂掉之后如何自愈

无人值守场景下,最怕的不是任务跑得慢,而是任务挂掉没人管。我实践中会做三层防护。

第一层是任务级别:在Open-AutoGLM配置里设置超时,超过时间就放弃当前分支,回到任务起点状态。有时候是目标App更新导致签到入口变了,模型反复找不到目标元素,此时与其无限重试不如直接放弃、写日志待查。

第二层是设备级别:每次任务开始前先做一次“前置体检”,检查包名是否存在:

adb shell pm list packages | grep com.example.app

如果包不见了,说明App被卸载或账号异常,直接拉停任务。还可以用pm uninstall --user 0 包名这种方式把应用状态重置为出厂状态,但这条命令要慎用,它会卸载当前用户的App数据。

第三层是系统级别:把任务丢进nohup后台跑,并在脚本里内置“看门狗”,每隔5分钟检查一次任务进程是否还在,不在就重新拉起。这样即使模型服务偶尔崩溃,整套任务还能自动恢复执行。我用了一个最简单的守护循环:

while true; do if ! pgrep -f "open_autoglm_task" > /dev/null; then nohup python open_autoglm_task.py > run.log 2>&1 & fi sleep 300 done

把这几层做好之后,我连续跑过一整个周末的自动测试任务,中途出现过一次页面加载超时,设备级防护自动把App重启并回到了任务起点,后面流程顺利完成。

5. 实测踩坑记录:从输入框失灵到数据目录权限墙

5.1 操作不响应时的排查顺序:先看状态再看路径

自动化跑着跑着突然“失灵”,最常见的是以下几种情况:

  • 屏幕灭了或者锁屏了,ADB命令还在发,但点不到任何东西;
  • 弹窗盖住了目标元素,模型还傻傻点击原来坐标;
  • ADB键盘的焦点丢了,文字输入发到之前那个页面上;
  • 无线连接断开,所有命令报device offline。

我的经验是排查时一定按顺序来:先确认连接状态(adb devices),再截一张当前屏幕(screencap),然后去翻任务日志,看模型决策输出和实际执行动作之间差在哪里。大多数“不响应”都是环境问题而不是框架问题,把环境稳定住,自动化马上就活了。

这里有个细节值得单独说:坐标偏移。不同分辨率的设备上,同一个按钮的x和y完全不同。所以不要直接在配置里写死坐标,而是通过uiautomator dump导出的UI层级文件,动态解析目标控件的bounds属性。Open-AutoGLM底层如果是走图像识别,模型会自己估算坐标,但如果你自己拼脚本,一定要走UI层级解析:

adb shell uiautomator dump --compressed /sdcard/ui.xml adb pull /sdcard/ui.xml

然后从ui.xml里找到文本内容为“签到”的节点,提取它的bounds,再取其中心点作为点击坐标。这样换机型、换分辨率都不怕。

5.2 Android 11+的数据目录限制:为什么你读不到App的缓存文件

我这次实战里遇到的一个硬骨头,是访问目标App私有数据目录被拒绝。现象是执行命令读取应用缓存时报错,比如:

unable to chmod '/storage/emulated/0/Android/data/xxx': Operation not permitted

这句话翻译过来就是“操作不被允许”。从Android 11开始,系统对/storage/emulated/0/Android/data/下的目录做了强管控,普通应用(包括ADB shell的默认权限)不再允许随便看其他应用的数据目录。我遇到过想清理某游戏的缓存目录、想读取某个测试App生成的日志文件,结果全部撞上这面权限墙。

有价值的解决方案有三条:

  1. 如果目标App是debuggable的,可以用run-as以应用身份访问它自己的私有目录:
adb shell run-as com.example.app ls files
  1. 有些App的数据目录可通过“设置 > 应用 > 存储与缓存”导出到公共目录,但自动化场景下基本不可行;
  2. 如果设备已root,那就用root权限直接绕开限制,但这属于另一个话题了。

我在实际项目里的做法是:尽量让目标App自己把日志写到外部公共目录,比如/sdcard/Download/,或者通过ADB键盘在App内部手动触发导出功能。能不改系统就不改系统,这样整套自动化方案的可移植性才高。

5.3 弹窗打断、屏幕休眠和版本变化的三个意外

最后分享几个只有真实跑才能碰到的意外。

权限弹窗是最老套但也最常见的打断方式。App首次启动会问通知权限、位置权限、悬浮窗权限,每个弹窗都会让模型识别到的目标界面完全变样。对策是在任务开始前把所有能预授权的权限都先手工授予一遍,自动化跑的时候提前用appops或系统设置关闭不需要的系统级通知。

屏幕休眠问题我也提过,像svc power stayon true这种一条命令就能解决调试期间灭屏导致的自动化中断,我建议写在任务启动脚本第一行:

adb shell svc power stayon true

还有一个容易被忽略的是App版本更新的问题。上周还好好的“签到”按钮,这个周版本更新后文案变成了“立即签到”,模型如果依赖文本识别就可能找不到。这就要靠Open-AutoGLM的多模态能力了,纯文本dump找不到就靠截图识别,截图识别不到就靠模板匹配。我实际测下来,处理界面改版最好的策略不是试图一次识别对,而是让任务支持“代处理”:发现目标元素后先保存当前截图到异常文件夹,同时尝试多种定位方式(文本、UI节点、图标相似度),为后续人工审核留证据。

这些坑零零碎碎,但很多都是不看日志就想破头也发现不了的。把每一条记录下来,下次遇到同样问题十分钟内就能解决。

我自己跑下来最大的感受是,Open-AutoGLM这类框架的核心价值不在“能执行ADB命令”,而在于把模型对界面的理解能力和ADB这种底层控制通道真正拧成了一股绳。方案本身不难搭,难的是在各种真实设备上都跑得稳。最后分享一个实用小技巧:在每天任务启动前,先发一个Home键回到桌面,再关闭所有后台应用通知,然后才开始执行。这个动作看起来不起眼,却能替你挡掉一大半因为弹窗、页面错位导致的自动化失败。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询