尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

安卓手机自动化测试:基于Termux与uiautomator2的环境搭建与实战

安卓手机自动化测试:基于Termux与uiautomator2的环境搭建与实战 1. 项目概述在手机上构建自动化测试环境如果你是一名移动端测试工程师或者开发者可能经常需要在多台安卓设备上重复执行一些繁琐的UI操作比如回归测试、数据填充或者应用监控。传统的方案离不开一台性能强劲的电脑上面运行着ADB、Python环境和测试脚本。但有没有想过把整个自动化测试的“大脑”直接塞进手机里让手机自己测试自己或者让一台旧手机变成自动化测试机独立完成任务这就是我们今天要聊的利用Termux和uiautomator2在安卓手机上搭建一个完全自包含的自动化测试环境。Termux是一个强大的安卓终端模拟器和Linux环境应用它可以在不root手机的情况下提供一个近乎完整的Linux命令行体验。而uiautomator2则是基于Python的安卓UI自动化测试库它封装了谷歌官方的UIAutomator框架让我们能用更简洁的Python代码来控制手机。将这两者结合意味着你可以摆脱电脑的束缚仅凭一部安卓手机就能编写、调试和运行自动化测试脚本。这对于需要移动办公、设备资源有限或者希望构建低成本、分布式自动化测试集群的场景来说是一个非常酷且实用的思路。接下来我将带你从零开始一步步实现这个环境并分享我在实践中踩过的坑和总结的技巧。2. 环境准备与核心工具解析2.1 Termux手机上的Linux终端Termux并不是一个简单的终端模拟器它通过一个巧妙的“前缀prefix”系统在安卓的/data/data/com.termux/files/usr目录下模拟出了一个完整的Linux文件系统。你可以通过包管理器pkg来安装Python、Node.js、GCC等上千个软件包几乎就像在Ubuntu上使用apt一样。安装与基础配置首先你需要从F-Droid或Google Play商店安装Termux。这里有一个关键点强烈建议从F-Droid安装。因为Google Play版本的Termux可能已经停止更新而F-Droid仓库维护的版本更新更及时软件包也更丰富。安装后打开第一步不是急着装软件而是先更新软件源和基础包pkg update pkg upgrade -y这个命令会同步仓库索引并升级所有已安装的包到最新版本。接下来我们需要安装一些编译和运行Python库可能需要的依赖pkg install python python-pip clang libxml2 libxslt libjpeg-turbo openssl -y安装clang编译器是为了后续某些Python库如lxml可能需要从源码编译。libxml2和libxslt是lxml库的依赖而libjpeg-turbo则是一些图像处理库如Pillow所必需的。注意Termux的存储隔离。默认情况下Termux只能访问自身的应用数据目录。如果你想访问手机的内部存储如下载文件夹需要运行termux-setup-storage命令它会请求存储权限并在~/storage目录下创建指向手机内部存储的符号链接。2.2 uiautomator2Python化的UI自动化利器uiautomator2简称u2是一个Python第三方库它通过HTTP协议与运行在手机上的一个守护进程atx-agent通信从而间接调用安卓系统的UIAutomator服务。这种架构带来了几个巨大优势脱离USB线缆通信基于网络可以通过Wi-Fi连接实现真无线自动化。跨平台只要手机和运行脚本的机器在同一个网络控制端可以是电脑、另一部手机甚至服务器。Pythonic API相比原生UIAutomator的Java API或冗长的ADB命令u2的API更加简洁直观。它的核心工作原理是在手机上安装一个名为atx-agent的守护进程应用以及一个用于提供UI控件信息的辅助应用com.github.uiautomator。测试脚本通过Python库向atx-agent发送HTTP请求atx-agent再通过ADB命令或直接调用系统API来执行操作。2.3 ADB不可或缺的桥梁虽然我们的终极目标是摆脱电脑但在初始环境搭建阶段ADBAndroid Debug Bridge仍然是必不可少的工具。我们需要通过电脑的ADB来为手机开启调试模式、安装必要的APK并完成uiautomator2环境的初始化。电脑端ADB环境准备从安卓开发者官网下载“Platform-Tools”包解压后将其路径例如D:\platform-tools添加到系统的环境变量PATH中。在手机上进入“开发者选项”通常在关于手机-版本号上连续点击7次开启并启用“USB调试”。用USB线连接手机和电脑在电脑命令行执行adb devices。首次连接时手机会弹出RSA密钥指纹确认对话框点击“允许”。如果遇到adb devices列表中出现unauthorized说明没有授权。请检查手机屏幕是否有确认弹窗或者尝试重启ADB服务adb kill-server adb start-server并重新插拔USB线。3. 完整环境搭建与初始化实战3.1 在Termux中安装Python及uiautomator2库确保Termux已经完成基础更新后我们开始安装Python环境。Termux的pkg安装的Python已经是较新的版本直接使用即可。pkg install python -y安装完成后验证一下python --version # 输出类似Python 3.11.4接下来使用pip安装uiautomator2库。由于Termux环境特殊某些依赖可能需要从源码编译过程可能会稍慢。pip install --upgrade pip pip install uiautomator2实操心得在Termux中安装uiautomator2时可能会遇到编译lxml库失败的问题。如果报错提及缺少libxml2或libxslt请确保你已经按照前面所述安装了libxml2和libxslt这两个包。如果仍然失败可以尝试先安装lxml的二进制轮子wheelpip install lxml然后再安装uiautomator2。3.2 初始化手机端uiautomator2环境这是最关键的一步需要在电脑的协助下完成。核心是使用uiautomator2提供的命令行工具将atx-agent和测试辅助APP推送到手机上。首先在电脑上需要已安装Python和uiautomator2库打开命令行执行初始化命令# 确保手机通过USB连接且adb devices可识别 python -m uiautomator2 init这个init命令会做以下几件事检查连接设备的ADB状态。将atx-agent可执行文件推送到设备的/data/local/tmp目录并赋予执行权限。在设备上启动atx-agent服务。自动下载并安装辅助APPcom.github.uiautomator和com.github.uiautomator.test。在设备上开启atx-agent服务的自启动。常见问题与排查init过程卡住或报错检查网络连接因为需要从GitHub下载文件。如果网络不畅可以尝试使用镜像源或者手动下载相关APK进行安装。辅助APP安装失败可能是手机上存在旧版本或冲突的APP。可以尝试先用adb uninstall com.github.uiautomator和adb uninstall com.github.uiautomator.test卸载再重新执行init。atx-agent启动失败执行adb shell /data/local/tmp/atx-agent version查看版本或用adb shell ps | grep atx-agent检查进程是否存在。初始化成功后你可以断开USB线了。此时手机上已经运行着atx-agent服务默认监听7912端口。3.3 在Termux中连接并控制手机现在回到Termux。我们需要让Termux里的Python脚本能够连接到手机上的atx-agent服务。由于两者都在同一部手机内我们可以使用本地环回地址127.0.0.1进行连接。首先我们需要将电脑ADB端口转发到Termux环境内部。但更优雅的方式是利用uiautomator2的connect方法它可以通过ADB自动建立端口转发。不过Termux内部没有原生的ADB。这里有两种方案方案一在Termux内安装ADB推荐实现完全独立Termux的仓库里提供了android-tools包其中包含了ADB。pkg install android-tools -y安装后你需要确保Termux能连接到安卓系统的ADB守护进程。这通常需要你的手机已获取root权限因为非root应用无法直接访问adb daemon。对于非root手机这个方案行不通。方案二通过无线ADB连接通用方案这是更可行的方案。我们先用电脑的ADB开启手机的无线调试端口然后让Termux通过Wi-Fi连接。用电脑开启无线调试# 确保USB连接 adb tcpip 5555 # 断开USB线 adb connect 手机IP地址:5555 # 例如adb connect 192.168.1.100:5555在Termux中使用纯Wi-Fi模式连接 此时Termux脚本中连接设备时不再依赖Termux本地的ADB而是直接指定设备的IP和端口。import uiautomator2 as u2 # 方法1通过设备的无线IP连接需确保电脑adb connect成功且手机与Termux在同一网络 d u2.connect(192.168.1.100:5555) # 方法2更佳利用同一设备内的环回地址和atx-agent端口 # 首先我们需要知道atx-agent的HTTP服务端口。默认是7912。 # 但u2.connect()函数设计用于网络连接。对于同一设备我们可以用‘adb shell’模式但这又需要ADB。 # 因此最稳妥的方法是在Termux脚本中通过subprocess调用系统ADB命令如果手机已root或者坚持使用无线连接模式。一个折中的实践方案对于非root手机最稳定的方式是将Termux环境与uiautomator2控制端分离。即用电脑或另一部手机作为控制中心运行主测试脚本和调度逻辑而被测手机安装了Termux和u2环境则作为一个“执行节点”运行接收指令并执行简单操作的“从脚本”。主控端通过Wi-Fi向执行节点发送HTTP请求调用atx-agent的API来触发操作。这样Termux在手机上的角色更像是提供了一个Python运行环境和任务接收器。4. 编写自动化测试脚本与核心API详解4.1 第一个脚本点亮屏幕并打开微信假设我们采用无线连接模式并且手机IP是192.168.1.100。在Termux中创建一个Python脚本test_demo.py#!/data/data/com.termux/files/usr/bin/python3 # -*- coding: utf-8 -*- import uiautomator2 as u2 import time def main(): # 连接设备 device_ip 192.168.1.100:5555 try: d u2.connect(device_ip) print(f成功连接设备: {d.info}) except Exception as e: print(f连接设备失败: {e}) return # 1. 唤醒屏幕 if not d.info.get(screenOn): d.screen_on() print(屏幕已唤醒) time.sleep(1) # 等待屏幕完全亮起 # 2. 解锁屏幕这里以滑动解锁为例实际密码解锁更复杂 d.unlock() print(已尝试解锁屏幕) # 3. 启动微信 d.app_start(com.tencent.mm) print(正在启动微信...) time.sleep(3) # 等待应用启动 # 4. 检查微信是否在前台 current_app d.app_current() if current_app[package] com.tencent.mm: print(微信启动成功当前位于前台。) else: print(f微信可能未启动成功当前应用是: {current_app}) # 5. 简单的点击操作假设点击“通讯录”选项卡需要先获取其坐标或选择器 # 这里需要先用weditor定位元素我们稍后讲解 # d(text通讯录).click() if __name__ __main__: main()脚本解析与注意事项d.info获取设备基本信息如屏幕状态、分辨率等。d.screen_on()点亮屏幕。如果屏幕已亮则无操作。d.unlock()尝试解锁。对于滑动解锁这个命令通常有效。对于图案、密码或指纹解锁需要更复杂的处理可能涉及d.swipe()模拟手势或结合其他自动化工具。d.app_start(package_name)通过包名启动应用。包名可以通过adb shell pm list packages | grep weixin等方式查找。d.app_current()返回当前前台应用的包名和活动Activity名。等待的重要性在UI操作之间尤其是启动应用、页面跳转后必须使用time.sleep()或更智能的d.wait_activity()、d.wait()等方法等待界面稳定否则后续操作很可能因为元素未加载而失败。4.2 元素定位使用Weditor进行可视化侦查编写UI自动化脚本的核心是精确地定位屏幕上的元素按钮、文本框、列表等。uiautomator2提供了多种定位方式text,resourceId,className,xpath等但如何知道一个元素的这些属性呢这就需要用到weditor。在电脑上安装并启动Weditorpip install --pre weditor python -m weditor执行后会自动打开浏览器。在页面顶部的输入框输入你手机的无线ADB地址如192.168.1.100:5555并点击“Connect”。连接成功后点击“Dump Hierarchy”按钮即可获取当前手机屏幕的UI层级结构并以可视化的方式展示。你可以点击页面上的任何元素右侧会显示该元素的所有可用定位属性。将Weditor用于Termux环境的技巧由于Termux没有图形界面无法直接运行Weditor。但你可以在电脑上用Weditor连接手机分析元素并记录下稳定的定位器优先使用resourceId其次text。将这些定位器直接写入在Termux中运行的脚本。例如用Weditor发现微信“发现”选项卡的resourceId是com.tencent.mm:id/icon并且它的instance属性是第几个。那么定位代码可以写成# 通过resourceId和instance定位instance从0开始 d(resourceIdcom.tencent.mm:id/icon, instance3).click()4.3 常用API与复杂交互操作掌握了元素定位就可以组合使用各种API来实现复杂操作。1. 点击与长按# 点击 element d(text搜索) element.click() # 或者直接链式调用 d(text搜索).click() # 长按 d(text某个会话).long_click(duration2.0) # 长按2秒2. 输入文本# 先定位到输入框再输入 d(resourceIdcom.tencent.mm:id/search_input).set_text(自动化测试) # 输入后可以发送回车键 d.press(enter)3. 滑动与拖动# 从坐标(x1, y1)滑动到(x2, y2)持续0.5秒 d.swipe(x1, y1, x2, y2, duration0.5) # 更常用的模拟上下左右滑动屏幕 d.swipe_ext(up) # 向上滑动 d.swipe_ext(down) # 向下滑动 d.swipe_ext(left, scale0.8) # 向左滑动滑动距离为屏幕宽度的80% # 拖动元素 draggable d(text可拖动项) draggable.drag_to(target_element, duration0.5)4. 等待与断言# 等待某个元素出现最多等10秒 d(text加载完成).wait(timeout10.0) # 等待某个元素消失 d(text正在加载...).wait_gone(timeout15.0) # 断言元素存在 assert d(text登录成功).exists5. 处理弹窗和权限自动化测试中系统弹窗如权限申请、更新提示是常见的干扰项。# 监听并自动处理弹窗在脚本开始时设置 d.watcher(ALLOW_PERMISSION).when(text允许).click() d.watcher(CONFIRM_UPDATE).when(text以后再说).click() # 启动监视器并设置检查间隔 d.watchers.start(interval2.0) # 每2秒检查一次 # 也可以手动处理 if d(text允许).exists: d(text允许).click()5. 实战构建一个简单的自动化测试任务让我们设计一个在Termux中运行的实际任务每日自动在某个新闻APP内完成签到和阅读任务。步骤分解环境检查确保网络连接屏幕已唤醒。启动目标APP。处理可能的启动广告。定位并点击“我的”或“个人中心”。在个人中心页面定位并点击“签到”按钮。处理签到成功弹窗。返回首页点击进入“推荐”或“要闻”列表。滑动阅读几篇文章模拟阅读行为。任务完成记录日志并退出APP。示例脚本框架import uiautomator2 as u2 import time import logging from datetime import datetime # 配置日志 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__) class NewsAppAutoTask: def __init__(self, device_ip): self.d u2.connect(device_ip) self.package_name com.example.newsapp # 替换为实际包名 logger.info(f初始化设备连接: {self.d.info}) def handle_popups(self): 处理常见弹窗可以在这里扩展 if self.d(text立即更新).exists: self.d(text以后再说).click() time.sleep(1) if self.d(text允许).exists: self.d(text允许).click() time.sleep(1) def sign_in(self): 执行签到操作 logger.info(开始执行签到任务) # 1. 点击“我的” if self.d(text我的).exists: self.d(text我的).click() time.sleep(2) else: # 可能图标是图片用resourceId定位 self.d(resourceIdcom.example.newsapp:id/tab_profile).click() time.sleep(2) # 2. 查找并点击签到按钮 sign_element self.d(textMatches.*签到.*) if sign_element.exists: sign_element.click() logger.info(点击签到按钮) time.sleep(3) # 3. 确认签到结果 if self.d(text签到成功).exists or self.d(text已签到).exists: logger.info(签到成功) return True else: logger.warning(签到结果未知) return False else: logger.warning(未找到签到按钮) return False def read_articles(self, count3): 模拟阅读文章 logger.info(f开始模拟阅读{count}篇文章) # 回到首页 self.d(resourceIdcom.example.newsapp:id/tab_home).click() time.sleep(2) for i in range(count): logger.info(f阅读第{i1}篇文章) # 点击列表中的第一篇文章根据实际情况调整定位器 if self.d(classNameandroid.widget.TextView, instance5).exists: self.d(classNameandroid.widget.TextView, instance5).click() else: # 备用方案点击屏幕中央区域 width, height self.d.window_size() self.d.click(width * 0.5, height * 0.3) time.sleep(5) # 阅读时间 # 上下滑动模拟阅读 for _ in range(3): self.d.swipe_ext(up, scale0.3) time.sleep(0.5) # 返回文章列表 self.d.press(back) time.sleep(2) def run(self): 主任务流程 try: # 唤醒屏幕 if not self.d.info.get(screenOn): self.d.screen_on() self.d.unlock() time.sleep(2) # 启动APP self.d.app_start(self.package_name) logger.info(f启动应用: {self.package_name}) time.sleep(5) # 等待应用启动和初始加载 # 处理初始弹窗 self.handle_popups() # 执行签到 self.sign_in() # 执行阅读任务 self.read_articles(count2) # 任务完成退出APP回到桌面 self.d.press(home) logger.info(自动化任务执行完毕) except Exception as e: logger.error(f任务执行过程中发生错误: {e}) # 可以在这里添加错误截图 self.d.screenshot(f/data/data/com.termux/files/home/error_{datetime.now().strftime(%Y%m%d_%H%M%S)}.png) if __name__ __main__: # 注意这里需要替换为你的设备实际IP task NewsAppAutoTask(192.168.1.100:5555) task.run()6. 进阶技巧与优化方案6.1 图像识别辅助定位在某些情况下UI元素没有稳定的resourceId或text属性比如游戏界面、自定义控件。这时可以引入图像识别作为补充。uiautomator2本身不包含图像识别功能但可以结合opencv-python和aircv等库来实现。在Termux中安装OpenCV在Termux中安装OpenCV有一定挑战因为涉及大量原生编译。可以尝试安装社区维护的版本pkg install opencv-python -y如果上述不可用可能需要从源码编译过程非常复杂。一个更简单的替代方案是使用pillow库进行简单的模板匹配精度较低或者将图像识别这部分功能放到服务器端处理手机端只负责截图和上传。简易图像匹配思路预先截取目标按钮的图片作为模板template.png。在脚本中当需要点击该按钮时先对当前屏幕截图d.screenshot().save(“current.png”)。使用pillow或opencv在current.png中查找template.png的位置。计算中心坐标并执行d.click(x, y)。6.2 使用Page Object模式组织代码当测试用例越来越多时将所有定位和操作堆砌在一个脚本里会难以维护。Page ObjectPO模式将每个应用页面抽象成一个类页面的元素定位和基本操作作为类的方法使测试逻辑更清晰。# base_page.py class BasePage: def __init__(self, d): self.d d # home_page.py from base_page import BasePage class HomePage(BasePage): property def search_box(self): return self.d(resourceIdcom.example.app:id/search_box) property def profile_tab(self): return self.d(resourceIdcom.example.app:id/tab_profile) def go_to_profile(self): self.profile_tab.click() return ProfilePage(self.d) # 返回下一个页面对象 # profile_page.py class ProfilePage(BasePage): property def sign_button(self): return self.d(text签到) def click_sign(self): self.sign_button.click() time.sleep(2)在测试脚本中调用起来非常清晰home HomePage(d) profile home.go_to_profile() profile.click_sign()6.3 定时任务与后台运行我们的目标是让手机自动执行任务因此需要让Termux在后台定时运行脚本。使用Termux的定时任务Termux支持cron但需要安装cronie包并启动服务。pkg install cronie编辑cron任务crontab -e添加一行例如每天上午9点15分执行15 9 * * * cd /data/data/com.termux/files/home /data/data/com.termux/files/usr/bin/python3 /data/data/com.termux/files/home/news_auto_task.py /data/data/com.termux/files/home/task.log 21保持Termux后台运行安卓系统可能会在锁屏后清理后台进程。为了防止Termux被杀死可以在手机设置中将Termux加入电池优化的“不优化”名单。使用Termux提供的termux-wake-lock工具获取唤醒锁。考虑使用Termux:Boot插件在设备启动时自动运行你的脚本服务。6.4 错误处理与日志收集稳定的自动化脚本必须包含完善的错误处理和日志记录。异常捕获使用try...except包裹可能失败的操作如点击、查找元素。断言与重试对于关键步骤使用断言检查结果并可以实现重试逻辑。截图功能在发生错误或关键步骤前后截图便于事后分析。try: d(text确定).click() except u2.UiObjectNotFoundError: logger.error(未找到‘确定’按钮) d.screenshot(/sdcard/error_confirm.png) # 需要Termux有存储权限 raise结构化日志像上面的示例一样使用Python的logging模块记录不同级别INFO, WARNING, ERROR的日志并输出到文件。7. 常见问题排查与性能优化7.1 连接与初始化问题问题现象可能原因排查步骤与解决方案u2.connect()超时1. 设备IP错误或不在同一网络。2. 设备上atx-agent未运行。3. 防火墙/安全软件阻止了端口。1.ping设备IP确认连通性。2. adb shell ps元素定位不到 (UiObjectNotFoundError)1. 元素属性动态变化。2. 页面未加载完成。3. 定位器写错。4. 屏幕状态不对如锁屏。1. 使用weditor实时查看当前层级确认属性。2. 添加等待d.wait(timeout10)或time.sleep()。3. 使用更稳定的定位方式如resourceId。4. 检查屏幕是否亮起并解锁。脚本执行速度慢1. 操作间等待时间(sleep)过长。2. 网络延迟Wi-Fi连接时。3. 手机性能不足。1. 用智能等待(wait)替代固定sleep。2. 尽量使用USB连接或优化网络。3. 关闭不必要的后台应用简化脚本逻辑。点击坐标不准确1. 设备分辨率与脚本坐标不匹配。2. 屏幕上有动态元素如通知栏。1. 使用相对坐标d.click(0.5, 0.5)点击屏幕中心。2. 使用元素定位器而非绝对坐标。3. 点击前确保界面稳定。7.2 稳定性提升技巧增加冗余操作和检查点对于重要的操作如点击登录按钮可以在点击后检查是否跳转到预期页面如果没有则重试。使用watcher处理意外弹窗在脚本开始前注册一些通用的弹窗监视器如处理权限申请、更新提示、网络异常等。定期重启atx-agent长时间运行后atx-agent可能出现内存泄漏或响应变慢。可以编写一个监控脚本定期如每天通过ADB重启该服务。多设备管理如果你用一部手机控制多部测试机可以考虑使用uiautomator2的Device列表功能并做好设备序列号或IP地址的映射管理。7.3 在Termux中管理多个Python项目随着脚本增多建议使用虚拟环境管理依赖。# 安装虚拟环境工具 pip install virtualenv # 为自动化测试项目创建虚拟环境 cd ~ python -m venv auto_test_env # 激活虚拟环境 source auto_test_env/bin/activate # 在虚拟环境中安装项目依赖 pip install uiautomator2 pillow requests # 运行脚本 python your_script.py # 退出虚拟环境 deactivate将激活环境和运行脚本的命令写在一个Shell脚本里便于通过cron调用。将Termux与uiautomator2结合确实为移动端自动化测试打开了一扇新的大门。它最大的价值在于“去中心化”和“低成本”。你可以将闲置的旧安卓手机改造成专用的自动化测试机7x24小时执行一些重复性的监控或验收任务而不必一直开着电脑。在实际部署中我建议将复杂的测试逻辑和调度放在更稳定的服务器或电脑上而手机端Termux只负责接收简单的指令并执行原子操作这样架构更清晰也更容易维护。这个方案在爬虫数据采集、APP每日任务自动化、简单的冒烟测试等场景下已经足够可靠。
返回列表