1. 为什么需要adb-easy-control?
作为一名长期在移动端自动化测试领域摸爬滚打的开发者,我深刻理解直接调用原生ADB命令行时的痛苦。每次都要手动拼接命令字符串、处理设备序列号、解析返回结果...直到发现这个宝藏工具包。adb-easy-control本质上是对Android Debug Bridge(ADB)的Python封装,它将繁琐的命令行操作转化为直观的方法调用。
这个包最吸引我的三个核心价值点:
- 设备管理自动化:自动识别连接设备,无需反复指定序列号
- 命令链式调用:支持类似
device.screen.on().unlock(1234)的流畅写法 - 异常处理内建:自动重连、超时控制等机制让脚本更健壮
在真实项目中,我用它实现了以下典型场景:
- 批量设备压力测试(同时操作20+台样机)
- 自动化冒烟测试(从开机到完成关键路径测试全流程)
- 竞品性能数据采集(规避反爬机制)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境配置与基础用法
2.1 安装的正确姿势
虽然pip install adb-easy-control看起来简单,但这里有三个容易踩的坑:
bash复制# 推荐使用清华源加速安装(国内环境)
pip install adb-easy-control -i https://pypi.tuna.tsinghua.edu.cn/simple
# 必须同时安装的依赖
brew install android-platform-tools # Mac
choco install adb # Windows
验证安装是否成功时,不要只看import能否执行。我习惯用这个检测脚本:
python复制from adb_easy_control import AdbController
def check_env():
ctrl = AdbController()
print("ADB路径:", ctrl.adb_path) # 应显示实际adb二进制位置
print("设备数:", len(ctrl.devices)) # 连接设备应≥1
try:
ctrl.execute("shell getprop ro.product.model")
return True
except Exception as e:
print(f"环境异常: {str(e)}")
return False
2.2 设备连接管理实战
处理多设备时,我推荐使用设备指纹(serial)而不是索引号:
python复制controller = AdbController()
devices = controller.devices # 获取所有设备对象
# 最佳实践:通过设备特征识别目标
target_device = next(
(d for d in devices
if "SM-G9880" in d.get_property("ro.product.model")),
None
)
if target_device:
print(f"找到目标设备: {target_device.serial}")
else:
print("未匹配到指定设备")
重要提示:在设备重启后serial可能变化,更可靠的方案是结合
ro.boot.serialno和ro.serialno综合判断
3. 核心API深度解析
3.1 设备控制链式调用
这个包的灵魂在于其流畅接口设计。以解锁设备为例,对比原生ADB与封装后的写法:
python复制# 原生ADB方式
os.system(f"adb -s {serial} shell input keyevent 26")
os.system(f"adb -s {serial} shell input swipe 500 1500 500 500")
os.system(f"adb -s {serial} shell input text 1234")
# adb-easy-control方式
(device
.power.wake_up()
.screen.unlock("1234")
.wait(1.5)) # 链式调用
关键类方法说明:
| 方法链 | 等效ADB命令 | 超时参数 |
|---|---|---|
power.off() |
adb shell reboot -p |
timeout=30s |
screen.capture() |
adb exec-out screencap -p |
timeout=15s |
input.tap(x,y) |
adb shell input tap x y |
timeout=5s |
3.2 智能等待机制
在自动化测试中最头疼的就是等待条件满足。这个包提供了三种等待策略:
python复制# 1. 固定时长等待(不推荐)
device.wait(3) # 简单但低效
# 2. 条件等待(最佳实践)
def is_launcher_shown():
return "launcher" in device.current_activity()
device.wait_until(is_launcher_shown, timeout=10, interval=0.5)
# 3. 混合等待(我的最爱)
with device.auto_wait(timeout=15):
device.app.start("com.tencent.mm") # 微信
device.input.swipe(...) # 滑动操作
# 每个操作会自动附加智能等待
4. 实战案例:微信自动化巡检
分享一个我用于微信兼容性测试的真实脚本框架:
python复制from adb_easy_control import AdbController
from datetime import datetime
class WeChatRobot:
def __init__(self):
self.ctrl = AdbController()
self.device = self.ctrl.first_device
def prepare_env(self):
"""清理测试环境"""
self.device.app.stop("com.tencent.mm")
self.device.files.remove("/sdcard/WeiXin/test_*.jpg")
def test_send_image(self, path):
"""验证图片发送功能"""
self.device.app.start("com.tencent.mm")
self.device.wait_until(
lambda: "chat" in self.device.current_activity(),
timeout=8
)
# 进入指定聊天
self.device.input.tap(360, 180) # 联系人位置
self.device.input.tap(720, 120) # 附件按钮
self.device.input.tap(240, 600) # 相册选择
# 选择图片
self.device.files.push(path, "/sdcard/Pictures/")
self.device.input.swipe(300, 800, 300, 200) # 滚动相册
self.device.input.tap(150, 300) # 选择最新图片
# 验证发送结果
last_msg = self.device.ui.get(
resource_id="com.tencent.mm:id/chat_time"
)
return datetime.now() - last_msg < timedelta(seconds=10)
避坑指南:
- 微信8.0+版本后,界面元素ID频繁变更,建议改用坐标点击
- 聊天列表的滚动操作需要根据设备分辨率调整参数
- 图片传输后需要额外1-2秒的编码时间
5. 高级技巧与性能优化
5.1 并行设备控制
当需要管理多台设备时,可以结合concurrent.futures实现并行:
python复制from concurrent.futures import ThreadPoolExecutor
def batch_install(devices, apk_path):
with ThreadPoolExecutor(max_workers=4) as executor:
futures = {
dev.serial: executor.submit(
lambda d: d.app.install(apk_path),
dev
)
for dev in devices
}
results = {
serial: future.result()
for serial, future in futures.items()
}
return results
5.2 命令执行优化
原生ADB每次执行都要建立新连接,我们可以复用连接提升性能:
python复制# 低效方式(每次独立命令)
for _ in range(100):
device.execute("dumpsys battery")
# 高效方式(会话保持)
with device.command_session() as session:
for _ in range(100):
session.execute("dumpsys battery") # 速度提升5-8倍
6. 调试与异常处理
6.1 常见错误代码
根据我的经验总结这些高频异常:
| 错误码 | 原因 | 解决方案 |
|---|---|---|
| ERR_DEVICE_OFFLINE | 设备未响应 | 检查USB调试授权 |
| ERR_ADB_VERSION | ADB版本冲突 | 更新platform-tools |
| ERR_TIMEOUT | 操作超时 | 调整wait_until参数 |
| ERR_SERVER | ADB服务崩溃 | 执行adb kill-server |
6.2 日志记录最佳实践
建议采用分层日志策略:
python复制import logging
logger = logging.getLogger("adb_controller")
logger.setLevel(logging.DEBUG)
# 控制台输出简洁信息
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 文件记录详细调试信息
file_handler = logging.FileHandler("adb_operations.log")
file_handler.setLevel(logging.DEBUG)
# 设备操作单独记录
device_logger = logging.getLogger("adb_device")
device_logger.addHandler(logging.FileHandler("device_commands.log"))
在长时间运行的自动化任务中,我还会添加内存监控:
python复制import psutil
def log_memory_usage():
process = psutil.Process()
logger.info(
f"内存占用: {process.memory_info().rss/1024/1024:.2f}MB"
)
# 定时记录(每10分钟)
import threading
def start_memory_monitor():
threading.Timer(600, log_memory_usage).start()
