ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Shizuku+ADB零Root自动化脚本实战:从无线调试到设备遍历

Shizuku+ADB零Root自动化脚本实战:从无线调试到设备遍历 1. 项目概述与整体方案1.1 先说清楚Shizuku和ADB是什么关系很多人听到Shizuku第一反应是又一个Xposed框架其实完全不是一回事。Shizuku本身不是一个Hook框架它是一个运行在Android系统上的服务进程帮你把ADBAndroid Debug Bridge的权限能力长期借用给普通App使用。换句话说Shizuku的本质是把ADB shell的权限通过系统服务的方式暴露给应用层让普通App能直接调用高权限API。ADB大家应该不陌生它是Android官方的调试桥电脑通过USB或无线网络连接手机后能用命令行做很多事情安装应用、抓日志、模拟点击、查看窗口层级、截图、改系统设置等。但它有个痛点——只能临时用电脑拔线就断。而Shizuku正好补上了这个缺口它把ADB的命令权限固定在系统进程里之后即使不用电脑App也能通过Shizuku调用这些能力。把这两者组合起来做自动化脚本本质上是解决一个问题在没有root权限的情况下如何稳定、长期地让手机替我们执行重复操作。无论是批量测试App、自动签到、爬取数据、或是做无障碍辅助这条路线都比root方案更安全、也更通用。1.2 这套方案能做什么做了快三年自动化相关工作我常用这套方案解决以下几类需求场景具体操作传统方式的问题ShizukuADB方案UI自动化测试启动App、模拟点击、截图比对需要root或MonkeyRunner通过uiautomator dump获取控件树精确点击系统状态监控抓取CPU频率、电池温度、网络状态需要root权限直接执行adb shell命令拿到实时数据批量任务批量安装/卸载应用、批量改设置逐个操作太慢脚本循环执行adb命令一台电脑控制多台设备无障碍辅助自动填写表单、自动切换应用需要开启无障碍服务用adb shell命令绕过部分限制我个人的看法是这套方案最大价值不在能不能做而在于普通开发者也能做。不需要编译内核、不需要解bl锁只要手机能开USB调试就能搭起一套自动化能力。2. 环境准备Shizuku安装与ADB工具链配置2.1 Shizuku安装的三种激活方式Shizuku的安装其实很简单GitHub Releases页面下载最新APK装上就行但激活方式有三条路需要根据自己手机情况选择。方式一无线调试激活Android 11及以上这一种是我目前最推荐的。Android 11开始系统内置了无线调试功能不需要电脑就能激活Shizuku。具体步骤如下手机开启开发者选项进入无线调试并打开点击使用配对码配对设备会弹出一个6位配对码用另一台设备或同一台手机的终端执行adb pair 手机IP:端口 配对码完成配对配对后在Shizuku App里点击通过无线调试启动即可这里有个细节配对用的端口和连接用的端口不一样。配对成功后无线调试界面会显示一个新的IP和端口这个才是后续连接用的。方式二ADB线连激活所有Android版本传统方式用USB线连接电脑adb devices adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh这条命令的本质是启动Shizuku服务进程。服务启动后Shizuku App里会显示正在运行。方式三root设备直接激活有root的手机最简单在Shizuku里直接点通过root启动选择授予root权限即可。这种方式的好处是重启后Shizuku会自动恢复不需要再手动激活。2.2 ADB工具链的下载与环境变量配置ADB工具通常从Android开发者官网下载platform-tools压缩包Windows用户要注意版本64位系统就用64位版本。下载后解压到一个固定目录比如D:\platform-tools。Windows环境变量配置打开系统属性 - 高级系统设置 - 环境变量在Path中加入D:\platform-tools然后打开新的CMD窗口输入adb version验证。如果提示adb不是内部或外部命令说明路径没配对。关于ADB版本不匹配的问题热词里提到adb server version (31) doesnt match this client (41)这个我后面会有专门章节讲排查方法。这里先说结论电脑端和手机端的ADB协议版本必须一致老旧手机的ADB协议版本可能落后需要手动更新platform-tools或者用兼容模式。2.3 手机端调试模式的正确打开方式开发者选项的开启方法各品牌不太一样但核心路径一致设置里连续点击版本号7次。需要注意小米/红米手机除了开启USB调试还要开启USB调试安全设置否则无法通过ADB模拟点击OPPO手机在开发者选项里要关闭权限监控vivo手机要在USB调试下再开USB调试安全权限华为/荣耀需要登录华为账号才能开启ADB调试这些细节不处理好后面跑自动化脚本会各种报错比如明明adb devices能看到设备但adb shell input tap就是没反应。3. 核心实操ADB命令与Shizuku的配合使用3.1 最常用的ADB命令清单做自动化脚本有几类命令是高频使用的。我这里整理了一份实用清单几乎每个自动化项目都会用到。设备连接与状态查询adb devices # 列出当前连接的设备 adb get-state # 获取设备状态device/offline/unauthorized adb shell getprop ro.product.model # 获取设备型号 adb shell getprop ro.build.version.release # 获取Android版本模拟操作adb shell input tap x y # 模拟点击坐标点 adb shell input swipe x1 y1 x2 y2 duration # 模拟滑动手势 adb shell input text hello # 输入文字不支持中文 adb shell input keyevent 4 # 模拟按键4代表返回键 adb shell input keyevent 3 # 模拟Home键窗口与UI层级adb shell uiautomator dump /sdcard/window_dump.xml # 导出当前窗口控件树 adb shell dumpsys window # 查看窗口焦点信息 adb shell wm size # 查看屏幕分辨率 adb shell wm density # 查看屏幕密度系统设置修改adb shell settings put system screen_brightness 200 # 设置屏幕亮度 adb shell settings put global stay_on_while_plugged_in 3 # 充电时常亮 adb shell wm set-user-rotation lock 1 # 锁定屏幕方向为横屏 adb shell locksettings set-disabled true # 关闭锁屏密码仅在测试设备上用截图与录屏adb exec-out screencap -p screen.png # 截图保存到电脑 adb exec-out screenrecord --time-limit 10 - video.mp4 # 录屏10秒保存到电脑这些命令看着简单但配合起来就是完整的自动化操作链。比如热词里提到adb截图保存电脑实际脚本中通常不是单独截图而是点击某个按钮 - 等待加载 - 截图 - 保存 - 下一步操作这样的流程。3.2 通过Shizuku授权应用执行Shell命令这里要区分一个概念直接用ADB执行命令和通过Shizuku让App执行命令场景完全不同。如果只是在电脑上操作直接adb就行但我们做自动化脚本往往需要手机上运行App由App来执行这些高权限命令。这时候Shizuku就派上用场了。Shizuku提供了一套APIApp可以通过它调用Runtime.exec()执行shell命令。具体代码逻辑以Android Java为例// 检查Shizuku是否就绪 if (!Shizuku.ping()) { // 引导用户去启动Shizuku Shizuku.requestPermission(ACTION_REQUEST_PERMISSION); return; } // 执行shell命令 private static String execShellCommand(String cmd) throws IOException { ParcelFileDescriptor pfd Shizuku.newProcess( new String[]{sh, -c, cmd}, null, null ); // 读取输出流 BufferedReader reader new BufferedReader( new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())) ); StringBuilder sb new StringBuilder(); String line; while ((line reader.readLine()) ! null) { sb.append(line).append(\n); } return sb.toString(); } // 示例获取当前前台应用的包名 String foregroundApp execShellCommand(dumpsys activity activities | grep mResumedActivity);用这种方式App就拥有了ADB shell级别的权限但不需要手机root也不需要在电脑上操作。实际项目中很多自动签到App、自动打卡工具就是这么实现的。3.3 用uiautomator dump实现精准点击坐标点击太脆弱屏幕分辨率一变脚本就报废。自动化脚本里真正的核心是根据控件ID或文本定位目标而不是固定坐标。uiautomator dump命令会把当前界面的控件树导出到XML文件里面包含了每个控件的包名、类名、文本内容、资源ID、坐标bounds等信息。解析这个XML就能精准定位并点击。实际操作流程# 第一步导出控件树 adb shell uiautomator dump /sdcard/window_dump.xml # 第二步将XML拉到电脑 adb pull /sdcard/window_dump.xml . # 第三步Python解析XML并执行点击Python侧的解析逻辑可以参考这个简版示例import xml.etree.ElementTree as ET import subprocess import re def parse_and_click(target_text): 解析控件树根据文本内容查找并点击 tree ET.parse(window_dump.xml) root tree.getroot() for node in root.iter(node): if node.get(text) target_text: bounds node.get(bounds) # 解析bounds格式[x1,y1][x2,y2] coords re.findall(r\[(\d),(\d)\], bounds) x1, y1 map(int, coords[0]) x2, y2 map(int, coords[1]) center_x (x1 x2) // 2 center_y (y1 y2) // 2 # 执行点击 subprocess.run([adb, shell, input, tap, str(center_x), str(center_y)]) print(f点击成功: {target_text} at ({center_x}, {center_y})) return True print(f未找到目标: {target_text}) return False # 使用示例 parse_and_click(确定)这里有个坑uiautomator dump在导出过程中会请求窗口权限偶尔会导致当前App失焦。解决办法是在dump前加一个小延时或者用adb shell uiautomator dump --compressed减少数据量。另外某些App做了防自动化检测控件树可能是加密的或者根本没有text属性这时候只能退回到坐标方案。注意uiautomator dump不支持在锁屏状态下执行如果做了locksettings set-disabled true关闭锁屏截图和dump都会顺畅很多。3.4 无线调试摆脱数据线束缚自动化脚本要真正方便必须用无线连接。无线调试有两种模式区分清楚能少踩很多坑。模式一Android 11内置无线调试这是目前最推荐的不依赖电脑直接在手机端设置里开启无线调试然后用Shizuku的无线调试启动按钮就行。但要注意一个问题无线调试默认只在Wi-Fi环境下生效且部分品牌的手机在锁屏一段时间后会断开无线调试需要到设置里关闭休眠时断开连接之类的省电选项。模式二传统ADB over Wi-FiAndroid 10及以下版本手机连接到同一局域网后用以下命令开启无线ADBadb tcpip 5555 adb connect 192.168.1.100:5555执行adb tcpip后手机会重启ADB服务然后就可以拔线了。这里有个容易踩的坑重启手机后无线ADB会回到关闭状态需要重新用USB线执行一次adb tcpip。所以如果是频繁重启的设备建议用Shizuku的方式它能在每次开机后自动打开无线调试。4. 实战案例用ShizukuADB写一个自动化测试脚本4.1 场景设定自动遍历App核心页面为了把前面的知识点串联起来我设计一个实际案例对一个测试App进行自动化遍历自动进入每个Tab页面截图保存到电脑同时记录页面加载时间和是否有报错日志。这个场景在企业App回归测试中特别常见新版本发布前手动点一遍几十个页面太耗时用脚本十几分钟就能搞定。4.2 脚本完整实现与参数解析整个脚本分为三步连接设备、执行遍历、处理结果。我用Python写了一个完整的可运行版本此处为演示核心逻辑#!/usr/bin/env python3 import subprocess import time import os from datetime import datetime DEVICE_IP 192.168.1.100 DEVICE_PORT 5555 APP_PACKAGE com.example.demoapp OUTPUT_DIR screenshots_ datetime.now().strftime(%Y%m%d_%H%M%S) # 步骤一连接设备 def connect_device(): # 先把设备添加到adb信任列表 subprocess.run([adb, connect, f{DEVICE_IP}:{DEVICE_PORT}]) # 等待连接稳定 time.sleep(2) result subprocess.run([adb, devices], capture_outputTrue, textTrue) print(result.stdout) if device not in result.stdout: raise Exception(设备连接失败请检查IP和端口) # 步骤二启动App并等待加载 def launch_app(): subprocess.run([adb, shell, monkey, -p, APP_PACKAGE, -c, android.intent.category.LAUNCHER, 1]) time.sleep(5) # 等待应用启动 # 步骤三遍历并截图 def traversal_pages(): if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) # 定义需要遍历的页面坐标根据实际App调整 tab_coords [ (100, 1800, 首页), (300, 1800, 分类), (500, 1800, 发现), (700, 1800, 消息), (900, 1800, 我的), ] for x, y, page_name in tab_coords: # 点击底部Tab subprocess.run([adb, shell, input, tap, str(x), str(y)]) time.sleep(3) # 等待页面完全加载 # 截图并保存到电脑 screenshot_path os.path.join(OUTPUT_DIR, f{page_name}.png) with open(screenshot_path, wb) as f: result subprocess.run( [adb, exec-out, screencap, -p], capture_outputTrue ) f.write(result.stdout) print(f已保存: {screenshot_path}) # 抓取日志检查是否有异常 logcat_output subprocess.run( [adb, logcat, -d, -s, AndroidRuntime:E], capture_outputTrue, textTrue ).stdout if FATAL EXCEPTION in logcat_output: print(f警告: {page_name} 页面出现崩溃异常) # 关闭App subprocess.run([adb, shell, am, force-stop, APP_PACKAGE]) if __name__ __main__: connect_device() launch_app() traversal_pages() print(自动化遍历完成)这个脚本有几个关键参数需要着重说明延时参数的选择点击Tab后为什么要等3秒因为页面加载速度跟设备性能和网络环境有关。太短会截到空白页太长浪费时间。我一般会先跑一次手动计时取平均加载时间加1秒余量。也可以在循环里做动态判断比如循环检测某个控件的出现但这会增加脚本复杂度。截图用exec-out而不是shelladb shell screencap -p file.png在Windows上会把文件结尾的\r\n错误地转成\n导致照片格式损坏。用adb exec-out可以绕过这个问题二进制数据原样输出。这个坑坑过我一次特此说明。日志筛选-s AndroidRuntime:E表示只看AndroidRuntime标签的错误日志。这样能快速定位崩溃异常不会被大量无用的系统日志淹没。配合Shizuku使用时可以把这些步骤从电脑ADB换成手机AppShizuku。具体做法是在App里把这几个Python步骤对应的shell命令封装起来然后通过Shizuku API执行效果几乎一致但完全不需要电脑介入。4.3 从脚本到平台的进阶多设备并行单台设备的自动化只是基础实际测试场景往往是一台电脑控制多台手机同时跑脚本。这时代理连接和管理策略就很重要了。ADB支持多设备连接但命令需要用-s参数指定具体设备adb devices # 查看所有设备 adb -s 192.168.1.100:5555 shell input tap 100 100 adb -s SERIAL_NUMBER shell screencap -p device1.pngPython脚本里可以用线程或进程池做并发控制但要注意多个设备同时执行uiautomator dump时如果设备性能一般偶尔会有冲突。稳妥的做法是加个全局锁让每个设备的dump操作串行执行。关于多设备并行我的经验是先用2到3台设备跑通流程确认脚本稳定后再扩展到更多设备。一次性上20台设备如果脚本里有某个隐藏bug崩溃起来排查会非常痛苦。4.4 开机自启与实际部署的完整闭环脚本写出来不算完关键是要能稳定运行。我常用的部署组合是**Tasker或Automate**在手机上定时触发脚本Termux作为shell脚本的运行环境通过Shizuku授予Termux执行高权限命令的能力这样手机上就形成了一个闭环早上8点自动触发自动化任务数据通过HTTP请求或邮件发送到指定服务器全程无人值守。热词里提到Termux安装ADB驱动并给其他手机刷机其实Termux对这个素材的用法原理上是一致的——Termux提供了Linux环境配合Shizuku就能在不root的情况下做很多本来需要root才能做的事。5. 常见问题排查与避坑指南5.1 高频问题速查表做ADB自动化有一些问题几乎每个人都会遇到。我把它们整理成了速查表按出现频率排序。问题现象可能原因解决方案adb unauthorized手机USB调试授权弹窗没点允许拔线重新连接或执行adb kill-server后重新adb devicesadb server version (31) doesnt match this client (41)电脑端和手机端ADB版本不一致更新电脑端platform-tools或卸载手机端第三方的ADB工具daemon not running... could not read ok from adb server端口5037被占用杀进程释放端口netstat -ano找PIDtaskkill /F /PID xxx无线调试连不上防火墙拦截端口5555检查电脑和手机是否在同一网段关闭防火墙测试uiautomator dump导出的XML是空的当前页面需要滚动或App做了防自动化先input swipe强制刷新布局检查是否锁屏状态截图显示全黑屏幕已熄灭或App在后台先执行input keyevent 224唤醒屏幕等待1秒再截图模拟点击无效部分品牌手机USB调试权限受限小米/OPPO/vivo需额外开启USB调试安全权限脚本执行到一半设备掉线USB线接触不良或休眠断网换高质量数据线手机设置里关闭Wi-Fi休眠用Shizuku保持连接5.2 深挖两个疑难问题adb unauthorized反复出现这个问题的本质是RSA密钥指纹不匹配。首次连接时电脑会生成一个RSA密钥对把公钥发给手机手机弹窗让你确认信任。如果弹窗没点允许或者点了否这个信任关系就没建立。处理办法是# 1. 杀掉ADB服务重新来过 adb kill-server adb start-server # 2. 重新连接手机注意看手机屏幕上的授权弹窗 adb devices如果拔线重连多次还是unauthorized那问题可能出在手机的开发者选项里曾经关闭过USB调试或者手机端存储了旧的密钥记录。部分品牌手机需要进入开发者选项关闭USB调试再重新打开才能清除旧的加密数据。5037端口被占用这个问题多发生在电脑上装了两个ADB工具比如手机助手自带的ADB和官方platform-tools两个版本的ADB服务进程抢同一个端口。Windows下的排查方法netstat -ano | findstr 5037找到PID后进任务管理器结束那个进程。如果找不到明确进程直接用安全模式关闭所有可能占用5037的程序再重启ADB。注意这个错误提示里出现的could not read ok from adb server往往是在adb start-server时出现的原因是老进程还在新进程无法正常建立连接。务必先杀干净再启动。5.3 设备厂商的定制化坑不同手机厂商对ADB的魔改程度差别很大。我有一次用一加手机跑自动化脚本前30分钟一切正常某一步突然adb shell input tap完全没有反应但adb devices显示设备状态正常。排查了半天发现是ColorOS的系统权限管理把模拟点击当成了高风险操作需要手动在权限管理里授予ADB模拟点击的权限。不同品牌的解锁姿势汇总三星开发者选项开启开发人员选项再开启监控和指针位置USB调试授权一次后基本稳定荣耀/华为新版本必须插上SIM卡并登录华为账号否则开发者选项不保存摩托罗拉部分设备需要开启允许模拟点击权限老款创维网络盒子需要在工厂模式里开启ADB方法不同型号差异极大通常要按遥控器组合键做得久了你会发现一台手机上跑通的自动化脚本换台手机可能要改一晚上。这不是脚本本身的问题而是各家ROM对ADB权限管制的差异。5.4 日志抓取与崩溃定位热词里提到adb logcat 抓取日志这是自动化脚本调试的核心手段。分享一个我常用的日志采集思路# 清空日志缓冲 adb logcat -c # 带时间戳启动App并采集指定进程的日志 adb shell am start -W -n com.example.app/.MainActivity adb logcat -v time -s com.example.app:V AndroidRuntime:E app_log.txt # 跑完自动化后停止日志采集CtrlC看日志时我主要关注三类异常FATAL EXCEPTION程序崩溃通常是空指针或资源找不到ANR in com.example.app主线程卡死多半是网络请求或数据库操作阻塞了UI线程SecurityException权限问题需要检查Shizuku有没有正确授权对自动化脚本来说SecurityException是最常见的失败原因。如果脚本是通过Shizuku执行命令但某个特定操作提示无权限多半是Shizuku权限被系统收回了去Shizuku App里重启服务即可。6. 一些私人经验和建议做了这么久ADB自动化最深的感触是这套技能真正的分水岭不在于会敲几条命令而在于能不能把命令组合成一套可靠的任务流程。命令是固定的但流程里的每个延时、每次异常处理、每一步失败重试才是自动化脚本的灵魂。给刚开始接触的朋友几个建议第一先把基础命令在命令行里跑熟再写脚本。我见过太多人一上来就写Python脚本一个adb devices都没在终端里手动执行过结果脚本报错分不清是Python语法问题还是ADB命令问题。第二善用延时和重试机制但不要滥用。每次操作之间加一秒钟延时能解决大部分偶发问题但也会让脚本执行时间成倍增加。我一般把基础延时设为1到2秒对页面加载时间长的场景单独做条件等待。第三脚本的关键步骤一定要打印日志。加一行print可能只花一秒但出了问题能帮你省一小时的排查时间。Shizuku和ADB的组合短期内不会过时。Android系统每次迭代都在收紧权限管控但ADB调试通道始终是开发者保留的后门。学会合理地利用这个通道能帮你省下大量重复的机械操作时间。下一步我准备在这个基础上继续研究如何结合LLM做一些更智能的自动化决策目前已经在看相关方向了。
返回列表