【大前端】【Android】用 Python 脚本模拟点击 Android APP —— 全面技术指南

用 Python 脚本模拟点击 Android APP ------ 全面技术指南

在自动化测试、自动操作、RPA 或数据采集场景中,经常需要在 PC 上用 Python 控制 Android 设备进行点击、输入、滑动等操作。本文从零开始全面介绍几种常见方案:ADB、uiautomator2、pure-python-adb、Appium,以及控件定位、UI dump 解析、坐标适配与稳定性优化等工程实践。


📑 目录


背景与原理速览

PC 控制 Android 的核心方法包括:

  • ADB input :执行 input tapinput swipe 等命令模拟触摸事件

  • uiautomator:从 Android UI 层读取控件树,按 resource-id/text 定位控件

  • Appium:跨平台自动化框架,基于 WebDriver

  • pure-python-adb:用 Python 原生实现 adb 协议

不同方法侧重点不同:

ADB 轻量、快速,但定位基于坐标;uiautomator2 和 Appium 提供 UI 树级别的稳定定位方法。


准备工作

  1. Android 设备已开启 USB 调试

  2. PC 可以执行 adb devices

  3. Python 环境(≥3.8)

  4. 常用包(按需安装):

    pip install uiautomator2
    pip install pure-python-adb
    pip install Appium-Python-Client


方法一:ADB 命令(最简单 & 最通用)

这是最基础也最兼容的方式。

📌 Python 调用 ADB 执行点击

复制代码
import subprocess
import time

ADB = "adb"

def adb(cmd: str):
    full = ADB.split() + cmd.split()
    return subprocess.check_output(full).decode('utf-8')

def tap(x, y):
    adb(f"shell input tap {x} {y}")

def swipe(x1, y1, x2, y2, duration=300):
    adb(f"shell input swipe {x1} {y1} {x2} {y2} {duration}")

tap(200, 800)
swipe(300, 1200, 300, 400, 500)

📌 获取屏幕分辨率

复制代码
adb shell wm size
# Physical size: 1080x2400

✔️ 优点

  • 无需额外安装

  • 非常快

  • 全机型高兼容性

❌ 缺点

  • 依赖坐标,UI 改动或分辨率不同都会失效

  • 无法直接基于控件定位


方法二:uiautomator2(更稳定的控件定位方式)

最推荐的 Python 自动化方案,支持资源 id、text、xpath 定位控件。

📌 安装初始化

复制代码
pip install --upgrade uiautomator2
python -m uiautomator2 init

📌 Python 示例

复制代码
import uiautomator2 as u2
import time

d = u2.connect()  # USB 或 IP 连接

# 启动 app
d.app_start("com.example.app")

# 通过 resource-id 选择控件
d(resourceId="com.example.app:id/login").click()

# 通过 text
d(text="下一步").click()

# dump 当前界面 XML
xml = d.dump_hierarchy()
print(xml[:500])

✔️ 优点

  • 最易用且最稳

  • 能获取控件信息

  • 支持 xpath、手势、多点触控

❌ 缺点

  • 设备需安装 uiautomator2 服务

  • 某些深度定制系统可能不稳定


方法三:pure-python-adb 与 adb shell 结合

适合需要 programmatic adb 的场景,不用频繁创建进程。

📌 安装

复制代码
pip install pure-python-adb

📌 示例代码

复制代码
from ppadb.client import Client

client = Client(host="127.0.0.1", port=5037)
device = client.devices()[0]

# 点击
device.shell("input tap 200 800")

# dump UI
device.shell("uiautomator dump /sdcard/uidump.xml")
device.pull("/sdcard/uidump.xml", "uidump.xml")

方法四:Appium(企业级自动化)

适合复杂 UI 自动化 / 多设备并发 / 测试平台集成。

📌 Python 代码示例

复制代码
from appium import webdriver
from selenium.webdriver.common.by import By

caps = {
    "platformName": "Android",
    "deviceName": "device",
    "appPackage": "com.example.app",
    "appActivity": ".MainActivity",
}

driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.find_element(By.ID, "com.example.app:id/login").click()
driver.quit()

✔️ 强大且标准

❌ 部署复杂,需要 Appium Server


控件定位方式:坐标 / id / text / xpath / UI Dump

🟢 推荐优先级

  1. resource-id(最稳定)

  2. text

  3. className + index / 层次

  4. xpath(慢但通用)

  5. 屏幕坐标(最不稳定,但简单)


不同分辨率适配(坐标比例换算)

如果必须用坐标,建议做分辨率适配。

📌 坐标换算函数

复制代码
def scale(x, y, base_w, base_h, w, h):
    return int(x * w / base_w), int(y * h / base_h)

📌 获取分辨率

复制代码
adb shell wm size

稳定性与同步策略(等待/重试/断言)

建议实践:

  • 不要到处用 sleep

  • 使用条件等待:exists(timeout=...)

  • 加入 retry(网络波动、动画会导致不稳定)

  • 操作后做断言(比如检查文本是否出现)

  • 失败时保存截图 + UI dump

示例:带重试的点击

复制代码
def click_retry(d, selector, tries=3):
    for i in range(tries):
        if d(selector).exists(timeout=2):
            d(selector).click()
            return True
    return False

常见问题与排查技巧

现象 排查方向
设备无响应 / 一直 unauthorize 重插 USB,确认授权弹窗
点击不生效 坐标不对 / 目标被遮挡 / 动画未结束
uiautomator2 init 失败 重启设备 / 切换 USB 端口
dump 不到控件 可能是 SurfaceView / Flutter / WebView(可辅助 OCR)

安全与合规性提醒

  • 请确保你对目标设备和目标应用拥有合法操作权限

  • 不要用于绕过安全、刷量等非法用途

  • 企业环境中操作前注意数据与隐私保护


完整综合示例:从控件 dump 到点击

复制代码
import uiautomator2 as u2
import re
import time

d = u2.connect()

# 启动 app
d.app_start("com.example.app")

# 首选通过 text 点击
if d(text="确认").exists(timeout=3):
    d(text="确认").click()
else:
    # 备选:从 XML dump 找 bounds
    xml = d.dump_hierarchy()
    m = re.search(r'text="确认".*?bounds="(\[.*?\])"', xml)
    if m:
        bounds = m.group(1)
        nums = list(map(int, re.findall(r"\d+", bounds)))
        l, t, r, b = nums
        cx, cy = (l+r)//2, (t+b)//2
        d.click(cx, cy)

总结 & 下一步建议

  • 仅需简单点击时:ADB input 最快

  • 想稳定可维护:uiautomator2 强烈推荐

  • 需要分布式 / 测试体系:选 Appium

  • 避免硬编码坐标,优先使用 resource-id、text

  • 引入等待、重试、断言让脚本更稳

  • 借助 UI dump、截图、日志排查错误

相关推荐
计算机魔术师18 小时前
AI 写了一半代码,谁来背锅?Anthropic 的安全重构笔记
前端
深念Y18 小时前
RIO-UL00(EMUI 4.1 / Android 6.0.1 / arm64)开机自启动 sshd
android·linux·华为·安卓·chroot·sshd·emui
爱和冰阔落18 小时前
【MySQL 慢查询排查实战】列表接口逐渐变慢时,怎样从请求链路定位原因
android·数据库·mysql
明月_清风19 小时前
vLLM 深度实战:2026 年生产级 LLM 推理引擎完全指南
前端·后端·ai编程
风月说与山鬼19 小时前
七、uni-app页面与组件生命周期
前端·uni-app
高洁0119 小时前
智能体的“记忆”难题
python·深度学习·机器学习·transformer
绿岛之北19 小时前
Electron 安全第三章:URL 加载与 WebView
前端·electron
sunoo-22919 小时前
C 语言文件 IO 全攻略:从基础函数到实战踩坑(BMP 读取 + 词典查询)
linux·c语言·前端·笔记·vscode·学习
Shinner欣儿19 小时前
React18 并发渲染小记
前端
三十岁老牛再出发19 小时前
8月21日总结
c++·python