class心平气和头像

ADB 工具函数 Python 使用教程

环境准备

  1. 安装 Platform-Tools(官网下载) 并将其路径加入系统环境变量 PATH。
  2. 手机开启「开发者选项」中的「USB 调试」功能。

执行命令验证设备连接:

adb devices

输出中显示设备状态为 device 表示已授权成功。记录设备序列号,例如:3B158E00A3V00000。

核心函数:adb()

函数签名含义
def adb(cmd: str, check: bool = True) -> str
  • cmd: 要执行的 ADB 命令字符串,如 'shell ls /sdcard'、'pull a.jpg D:/a.jpg'。
  • check: 是否检查返回码。若为 True 且命令失败,抛出异常;若为 False,返回空字符串,脚本继续运行。
推荐实现
import subprocess
from pathlib import Path

DEVICE_SERIAL = "3B158E00A3V00000"  # 替换为你的设备序列号

def adb(cmd: str, check: bool = True) -> str:
    """执行 adb 命令。支持 shell、pull、push 等操作"""
    full_cmd = f"adb -s {DEVICE_SERIAL} {cmd}"
    result = subprocess.run(
        full_cmd,
        shell=True,
        capture_output=True,
        text=True,
        encoding="utf-8",
        errors="replace",
    )
    if check and result.returncode != 0:
        raise RuntimeError(f"ADB 失败: {full_cmd}\n{result.stderr}")
    return result.stdout.strip()
调用方式
# 检查错误(默认行为),失败则抛异常
brand = adb("shell getprop ro.product.brand")

# 允许失败,不中断脚本,返回空串
raw = adb("shell ls /sdcard/Pictures", check=False)

# 截图并拉取
adb("shell screencap -p /sdcard/screen.png")
adb(r'pull /sdcard/screen.png D:\screen.png')

常用工具函数

推送图片(固定文件名,避免相册乱序)
def push_image_to_phone(local_path: Path) -> str:
    # 步骤1:确保目录存在(不删除目录,保留 MediaStore 已有路径记录)
    adb(f"shell mkdir -p {PHONE_TMP_DIR}")

    # 步骤2:以固定文件名覆盖推送
    phone_path = f"{PHONE_TMP_DIR}/{PHONE_FIXED_FILENAME}"
    print(f"  [ADB PUSH] {local_path.name} → {phone_path}")
    adb(f'push "{local_path}" {phone_path}')

    # 步骤3:通知 MediaStore 重新扫描该路径,更新缩略图和索引
    adb(
        f"shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE "
        f"-d file://{phone_path}",
        check=False
    )
    return phone_path

拉取单个文件或目录
def pull_single_file(phone_path: str, local_dir: Path, rename: str = "") -> Path:
    local_dir.mkdir(parents=True, exist_ok=True)
    fname = rename or Path(phone_path).name
    local_dst = local_dir / fname
    adb(f'pull "{phone_path}" "{local_dst}"')
    return local_dst

获取手机目录下所有文件名(集合形式)
def get_phone_dir_files(directory: str) -> set[str]:
    raw = adb(f"shell ls {directory}", check=False)
    if not raw:
        return set()
    return {line.strip() for line in raw.splitlines() if line.strip()}

差量拉取新生成的图片
PHONE_DOWNLOAD_DIR = "/sdcard/Pictures"

def pull_new_images(before: set[str], output_dir: Path, prefix: str) -> list[Path]:
    after = get_phone_dir_files(PHONE_DOWNLOAD_DIR)
    new_files = after - before
    saved = []
    for fname in sorted(new_files):
        dst = output_dir / f"{prefix}_{fname}"
        adb(f'pull "{PHONE_DOWNLOAD_DIR}/{fname}" "{dst}"')
        saved.append(dst)
    return saved
用法示例
before = get_phone_dir_files(PHONE_DOWNLOAD_DIR)
# ... 触发 App 生成内容 ...
saved = pull_new_images(before, Path(r"D:\output"), prefix="case001")
print(f"已保存 {len(saved)} 张新图片")

Shell / 按键速用

adb("shell getprop ro.product.model")      # 获取设备型号
adb("shell input keyevent 4")              # 按返回键
adb("shell input keyevent 3")              # 按 Home 键
adb("shell input tap 540 960")             # 点击屏幕坐标 (540, 960)
adb("shell am force-stop com.larus.nova")   # 强制停止指定应用

最小可运行示例

# demo_adb.py
from pathlib import Path

DEVICE_SERIAL = "3B158E00A3V00000"  # 替换为你的设备序列号

# 粘贴以下函数定义:
def adb(cmd: str, check: bool = True) -> str:
    full_cmd = f"adb -s {DEVICE_SERIAL} {cmd}"
    result = subprocess.run(
        full_cmd,
        shell=True,
        capture_output=True,
        text=True,
        encoding="utf-8",
        errors="replace",
    )
    if check and result.returncode != 0:
        raise RuntimeError(f"ADB 失败: {full_cmd}\n{result.stderr}")
    return result.stdout.strip()

PHONE_TMP_DIR = "/sdcard/doubao_tmp"
PHONE_FIXED_FILENAME = "doubao_upload.jpg"

def push_image_to_phone(local_path: Path) -> str:
    adb(f"shell mkdir -p {PHONE_TMP_DIR}")
    phone_path = f"{PHONE_TMP_DIR}/{PHONE_FIXED_FILENAME}"
    adb(f'push "{local_path}" {phone_path}')
    adb(
        f"shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE "
        f"-d file://{phone_path}",
        check=False,
    )
    return phone_path

def get_phone_dir_files(directory: str) -> set[str]:
    raw = adb(f"shell ls {directory}", check=False)
    if not raw:
        return set()
    return {line.strip() for line in raw.splitlines() if line.strip()}

if __name__ == "__main__":
    print("brand =", adb("shell getprop ro.product.brand"))
    print("model =", adb("shell getprop ro.product.model"))
    files = get_phone_dir_files("/sdcard/Pictures")
    print("Pictures count =", len(files))

运行前确保设备已连接且授权。


常见问题

问题解决方案
adb: command not found检查 Platform-Tools 是否正确安装并加入 PATH
error: device not foundUSB 连接不稳定,尝试重新插拔或重启 ADB (adb kill-server, adb start-server)
图片未出现在相册使用 am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE 手动触发扫描
中文输入无效改用 uiautomator2 的 set_text(),避免直接调用 input text
文件拉取失败(权限/路径)确保路径存在,使用 mkdir -p 创建目录,避免路径拼写错误

设计要点(写脚本时记住)

  • 所有 ADB 调用必须通过封装函数 adb() 统一入口,禁止直接拼写 adb -s xxx。
  • 可能失败的操作(如 ls 空目录、广播扫描)使用 check=False 防止脚本中断。
  • 推送图片使用固定路径覆盖,避免因文件名随机导致媒体库污染。
  • 拉取结果采用差量集合比对,防止误拉历史文件,保证数据准确性。
  • 路径处理统一使用 Path,避免字符串拼接错误。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2301_79482961/article/details/168863303

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--