【大前端】【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、截图、日志排查错误

相关推荐
Winter_Sun灬2 小时前
CentOS 7 编译安卓 arm64-v8a 版 OpenSSL 动态库(.so)
android·linux·centos
Arvin_Rong2 小时前
前端动态 API 生成与封装:前端 API 调用的一种思路
前端
龚礼鹏2 小时前
图像显示框架六——SurfaceFlinger的初始化以及任务调度(基于Android 15源码分析)
android
2401_860319522 小时前
DevUI组件库实战:从入门到企业级应用的深度探索,如何实现支持表格扩展和表格编辑功能
前端·前端框架
码界奇点2 小时前
基于Django与Vue.js的RBAC权限管理系统设计与实现
vue.js·python·车载系统·django·毕业设计·源代码管理
LYFlied2 小时前
从循环依赖检查插件Circular Dependency Plugin源码详解Webpack生命周期以及插件开发
前端·webpack·node.js·编译原理·plugin插件开发
翔云 OCR API2 小时前
赋能文档的数字化智能处理:通用文字/文档/合同识别接口
开发语言·人工智能·python·计算机视觉·ocr
电饭叔2 小时前
如何代码化,两点之间的距离
笔记·python·算法
壮哥_icon2 小时前
Android 使用 PackageInstaller 实现静默安装,并通过 BroadcastReceiver 自动重启应用
android·gitee·android-studio·android系统