ADB (Android Debug Bridge) 详解
无论你是做 App 爬虫自动化、逆向分析,还是 Android 原生 / 跨端开发,ADB(Android Debug Bridge)都是一把“移动端瑞士军刀”。它让你能像操控本地命令行一样操控手机:装应用、传文件、抓日志、截屏、端口转发……一条命令搞定。
这篇文章从零开始,用最直白的语言把 设备连接、文件传输、应用管理、Python 自动化 这几个核心场景讲透。让你不必零散查命令,看完就能上手。
一、设备管理篇:连接是第一步
新手最容易卡在 “unauthorized”(未授权)、“offline”(离线) 或者 设备列表一片空白。我们先把 USB 调试、WiFi 无线连接、常见问题排查一次性说清楚。
1.1 开启 USB 调试(避坑要点)
无论用 USB 还是 WiFi,手机都必须先弹出 “允许 USB 调试” 的授权弹框并确认。配置过程只需要做一次:
- 数据线:必须用“充电 + 数据传输二合一”的数据线,纯充电线无法识别。
- 开发者选项:进入「设置 → 关于手机」,连续点击 版本号 7 次,直到提示“已开启开发者选项”。
- 打开调试开关:返回「设置 → 系统(或更多设置)→ 开发者选项」,找到并开启以下两个选项:
- USB 调试
- USB 调试(安全设置)(部分系统叫“USB 安装”或“取消授权空白”等)
- 弹框确认:用数据线连接电脑后,手机会弹出“允许 USB 调试吗?”对话框,务必勾选“一律允许使用这台计算机进行调试”,再点击“确定”。
如果弹框死活不出来,或者显示 unauthorized,用下面这条“万能重启大法”:
# 停止 ADB 服务(能解决绝大多数授权和离线问题)
adb kill-server
# 重新启动 ADB 服务
adb start-server
之后再重新插拔数据线或重新连接 WiFi,弹框通常就会出现。
1.2 基础连接检查
连接上设备后,先用 adb devices 确认状态:
# 查看所有已连接设备的 ID 和状态
# device → 已授权,可以操作
# unauthorized → 未授权,需要手机上确认
# offline → 离线,一般是服务挂了或调试开关关闭
adb devices
# 只提取正常设备的 ID(写脚本时常用)
adb devices -l | awk 'NR>1 && /device/ && !/offline/ {print $1}'
1.3 WiFi 无线调试(解放数据线)
手机和电脑连在 同一个局域网(同一个 WiFi 或路由器下)就可以开启无线调试,以后不用再插线。
操作步骤:
# 1. 先通过 USB 连上设备,确认 adb devices 显示 device
# 2. 让手机监听 TCP/IP 端口(默认 5555)
adb tcpip 5555
# 3. 查看手机的局域网 IP 地址(任选一种命令)
# 方法 A:最通用,绝大多数机型可用
adb shell getprop dhcp.wlan0.ipaddress
# 方法 B:查看网卡信息,试试 wlan0 / eth0 / rmnet_data0
adb shell ifconfig wlan0
# 方法 C:Android 10 及以上更精准
adb shell cmd connectivity wifi status | grep "IpAddress"
# 4. 用 IP + 端口连接(替换成你手机的 IP)
adb connect 192.168.1.100:5555
# 5. 拔掉 USB 线,再次运行 adb devices 确认设备状态为 device
连接成功后,以后只要手机和电脑在同一个局域网,每次直接 adb connect <手机IP>:5555 就能连上。
提示:如果 WiFi 连接不上,可以先 adb kill-server && adb start-server 再试。另外有些系统重启后 5555 端口会关闭,需要再次用 USB 线激活一次。
二、文件传输篇:高速互传,不压画质
还在用微信 / QQ 传文件?不仅画质被压缩,速度还慢。ADB 的文件传输走数据线或局域网,速度取决带宽,非常适合传 APK、日志、测试数据。
常用命令:
# 将本地文件推送到手机
# /sdcard/ 开头是用户公共目录,不需要 root
adb push ./test_apk.apk /sdcard/
# 整个文件夹递归推送(-r)
adb push -r ./crawler_temp /sdcard/crawler_backup/
# 从手机拉取文件到本地
adb pull /sdcard/logcat_latest.txt ./
adb pull -r /sdcard/crawler_backup/ ./local_data/
# 增量同步(只传输有变化的文件,比全量 cp 更快)
adb sync # 同步 /sdcard 等公共分区
adb sync /system # 同步系统分区(需 root)
三、应用控制篇:App 爬虫的基本功
爬虫的第一步就是控应用:安装、卸载、获取包名、启动、强制停止,这些 ADB 都能完美支持。
3.1 安装与卸载
# 安装 APK
adb install ./test_apk.apk # 普通安装
adb install -r ./test_apk_v2.apk # 覆盖安装(保留数据)
adb install -d ./test_apk_v1.apk # 降级安装(签名要相同)
adb install -s ./test_apk.apk # 安装到 SD 卡(旧机型)
# 卸载应用
adb uninstall com.example.testapp # 普通卸载
adb uninstall -k com.example.testapp # 彻底卸载(删除所有数据)
实际使用中,install -r 和 uninstall -k 用得最多,前者用于版本迭代,后者用于重置应用环境。
3.2 查询应用信息(找包名、启动页)
# 列出所有安装的包
adb shell pm list packages # 全部(系统 + 第三方)
adb shell pm list packages -3 # 只看第三方(爬虫最常用)
adb shell pm list packages -s # 只看系统应用
adb shell pm list packages -f # 显示包对应的 APK 路径(方便逆向分析)
# 查看某个应用的详细信息
adb shell dumpsys package com.example.testapp
# 从 dumpsys 中快速提取关键信息
# 版本名
adb shell dumpsys package com.example.testapp | grep versionName
# 版本号
adb shell dumpsys package com.example.testapp | grep versionCode
# 启动 Activity(找带 LAUNCHER 的)
adb shell dumpsys package com.example.testapp | grep -A 5 "android.intent.category.LAUNCHER"
拿到包名和启动 Activity 后,就能精确控制应用启动,比用 monkey 更稳定。
3.3 启动与停止应用
# 强制停止(彻底杀掉进程)
adb shell am force-stop com.example.testapp
# 启动应用
# 方法一:指定组件名(最推荐)
adb shell am start -n com.example.testapp/.MainActivity
# 方法二:用 monkey 模拟点击图标(不知道启动 Activity 时备用)
adb shell monkey -p com.example.testapp -c android.intent.category.LAUNCHER 1
启动完应用后,就可以配合截图、录屏、日志等开始自动化工作。
四、Python 自动化控制:批量操作解放双手
单条命令效率太低,比如你要给 10 台手机安装同一个应用,或者每隔 5 秒自动截屏,手动敲命令太容易出错。用 Python 把 ADB 命令封装成类,不仅能批量处理,还可以灵活集成到爬虫流程里。
下面是一个轻量级的 ADB 控制器,基于 Python 自带的 subprocess 模块,无需安装任何第三方库,拿来即用。
import subprocess
import time
import os
from typing import Optional, List
class LightADB:
"""轻量级 ADB 控制器,专注 App 爬虫 / 日常自动化"""
def __init__(self, device_id: Optional[str] = None, timeout: int = 30):
self.device_id = device_id
self.timeout = timeout
self.available_devices = self._fetch_devices()
self.current_device = self._select_current_device()
print(f"✅ ADB 初始化完成,当前操作设备: {self.current_device}")
def _fetch_devices(self) -> List[str]:
"""获取所有已授权在线设备的 ID"""
try:
result = subprocess.run(
['adb', 'devices'],
capture_output=True, text=True, timeout=self.timeout
)
raw_lines = result.stdout.strip().split('\n')[1:]
return [
line.split('\t')[0]
for line in raw_lines
if '\tdevice' in line
]
except subprocess.TimeoutExpired:
print("⚠️ ADB 命令超时,请检查服务是否正常")
return []
except Exception as e:
print(f"❌ 获取设备列表失败: {e}")
return []
def _select_current_device(self) -> str:
"""选择当前要操作的设备"""
if not self.available_devices:
raise RuntimeError("❌ 未找到可用 ADB 设备,请检查连接和授权。")
if self.device_id and self.device_id in self.available_devices:
return self.device_id
return self.available_devices[0]
def _exec_cmd(self, cmd_list: List[str]) -> str:
"""执行 adb -s <serial> <cmd> 命令并返回输出"""
full_cmd = ['adb', '-s', self.current_device] + cmd_list
try:
result = subprocess.run(
full_cmd,
capture_output=True, text=True, timeout=self.timeout
)
if result.returncode != 0:
print(f"⚠️ 命令执行失败: {' '.join(full_cmd)}\n{result.stderr.strip()}")
return ""
return result.stdout.strip()
except Exception as e:
print(f"❌ 命令异常: {e}")
return ""
# ---------- 常用操作方法 ----------
def get_third_packages(self) -> List[str]:
"""获取所有第三方应用包名"""
output = self._exec_cmd(['shell', 'pm', 'list', 'packages', '-3'])
return [line.split(':')[1] for line in output.split('\n') if line.strip()]
def capture_screen(self, save_dir: str = "./adb_screenshots") -> Optional[str]:
"""
手机截屏并自动拉取到本地
:param save_dir: 本地保存目录,会自动创建
:return: 成功时返回图片路径,失败返回 None
"""
os.makedirs(save_dir, exist_ok=True)
timestamp = int(time.time())
temp_phone_path = f"/sdcard/adb_temp_{timestamp}.png"
local_path = os.path.join(save_dir, f"screen_{timestamp}.png")
# 1. 手机端截图
self._exec_cmd(['shell', 'screencap', temp_phone_path])
# 2. 拉取到电脑
pull_res = self._exec_cmd(['pull', temp_phone_path, local_path])
# 3. 删除手机临时文件
self._exec_cmd(['shell', 'rm', temp_phone_path])
if "pulled" in pull_res.lower():
print(f"✅ 截屏已保存: {local_path}")
return local_path
return None
# ================= 使用示例 =================
if __name__ == "__main__":
try:
adb = LightADB()
# 1. 查看前 3 个第三方应用
packages = adb.get_third_packages()[:3]
print(f"📱 前 3 个第三方应用: {packages}")
# 2. 每隔 2 秒截屏一次,连续截 3 次
for i in range(3):
adb.capture_screen()
if i < 2:
time.sleep(2)
except Exception as e:
print(f"❌ 示例运行失败: {e}")
这个最简控制器覆盖了连接管理、包名获取、截屏等高频操作。你可以根据自己的需求继续扩展:比如添加 tap、swipe、input 等方法,实现自动化点击、滑动和文字输入。
五、补充几个实用小技巧
5.1 端口转发
有时候我们需要把手机上的一个本地服务映射到电脑上。比如手机在 5000 端口跑了一个 HTTP API,用端口转发即可在电脑上通过 localhost:6000 直接访问。
# 将电脑 6000 端口转发到手机的 5000 端口
adb forward tcp:6000 tcp:5000
# 查看当前所有转发规则
adb forward --list
# 取消所有转发
adb forward --remove-all
这在调试远程接口、代理中间人抓包时非常有用。
5.2 清空日志缓冲区
爬虫或调试时,旧日志太多会干扰分析。先清空再开始抓日志,结果干净很多:
# 清空所有日志缓冲区
adb logcat -c
之后再用 adb logcat -s YOUR_TAG 抓指定标签的日志,就很清爽了。
ADB 是移动端调试的基石。上面这些命令和 Python 封装足以支撑大部分 App 爬虫和自动化需求。如果碰到更复杂的 UI 交互(比如需要点击按钮、滑动列表、输入文本),可以进一步结合 uiautomator2 或 Appium 这类高级框架,但底层还是离不开 ADB 的稳定连接和基础操作。
希望这篇详解能帮你顺利拿下移动端自动化这一关。