注:本文有参考一些网络文章实操写的,若存在侵权请联系删除~
IOS自动化之WDA
一、介绍
首先,了解一下app自动化的原理,请看下面的图,一目了然~
IOS自动化测试架构图:
稍微概括一下下,就是不论appium呀、facebook-wad呀,啥的上层做自动化的工具都是通过底层的一套系统自带的通用控制工具来实现自动化。比如IOS最终一定是通过WebDriverAgent调用XCUITest来实现自动化滴;android就是通过UIautomatic ATX来调用实现的。
所以!重点就是一定要安装这个底层的工具,不然上层再咋牛逼,都无用拉。就像火箭只有一个高逼格的外壳,没有发动机咋飞起来呢,对吧?
好了,开始介绍IOS自动化之旅~
二、环境准备少不了
IOS自动化需要的环境:
- 1.ios手机安装WebDriverAgent应用
- 2.电脑安装facebook-wda(mac or windows都可以):
- MAC电脑可以用xcodebuild启动WDA
- WIN电脑就需要借助tidevice启动了,但是tidevice可以横跨Linux、Windows 、MAC三界使用!
由于贫穷+用不惯MAC,我还是用win电脑来做IOS自动化,因此所需的环境如下:
MAC :macOS 14(仅用于ios手机安装WDA)-----ps:若没有MAC电脑就在windwos上装虚拟机+macOS
xcode: version 15
IOS手机:iphone X(16.6)
Windows系统:win10
方案一、通过MAC电脑+WIN电脑结合实现跑自动化脚本
首先需要通过MAC电脑给IOS安装WDA
给手机安装WebDriverAgent,一定要用MAC电脑或用虚拟机MAC系统安装,没有其他途径!!!踩过坑🕳了,听劝姐妹!
1、首先mac系统上安装XCode,直接appstore上下载安装即可,最好下最新版本吧,旧得版本可能不兼容新的机型,至少我遇到过就是。
2、下载WebDriverAgent:https://github.com/appium/WebDriverAgent
3、用XCode打开WebDriverAgent。
-
1.首先用xcode打开WebDriverAgent中的WebDriverAgent.xcodeproj文件,是xcode项目文件
-
2.xcode添加开发者账户。xcode-setting-Account,添加开发者账号
-
3.配置WDA环境,选择刚刚创建的Team账号,修改Bundle Identifier为唯一名称即可,随意。
-
4.设置完成后选择scheme为WDArunner
检查Destination是你连接的手机。
- 5.项目构建
点击页面左上角三角形icon,或点击product-build
构建成功之后,点击Test,就可以看到WebDriverAgent安装到了手机上。
注意:点击后会提示需要授权才能用,在手机的设置–通用–VPN于设备管理,点击信任app即可。
遇到的问题:各种各样的问题,点击查看
方案二、通过win电脑完成全程IOS环境搭建+跑自动化脚本
若无MAC电脑,通过win电脑结合虚拟机完成MAC系统+WDA环境搭建以及跑自动化脚本:具体环境搭建,点击查看
三、win电脑跑IOS自动化脚本必备
-
win电脑:
- 系统:win10
- pycharm: pycharm-community-2024.2.3
- python: python-3.13.0-amd64
- tidevice
- facebook-wda
- iTunes
-
IOS手机:
- 手机上已安装WebDriverAgent软件,并且可以正常启动。
ios上安装了WDA后,需要保证windows上有可以启动WDA的工具:facebook-wda,iTunes,tidevice
-
1.facebook-wda
原理分析:
WebDriverAgent是一个IOS移动测试框架。在IOS端实现了一个webDriver server,通过server连接XCUITestframework调用Apple的API实现远程控制。
WebDriverAgent采用C/S架构,集成appium使用的webdriver协议规范,通信协议使用MobileWire Protocol:- WDAClient: WDA客户端,facebook-wda就是wda的python客户端,通过 HTTP协议(Mobile JSON Wire Protocol)与WebDriverAgent通信。
- WebDriverAgentRunner: 运行在手机上的WDA server ,默认监听断开为8100,主要用来:①接受WDAClient的请求并将命令发送给XCTest.framework; ②将响应发送给WDA Client;
- 电脑上的wda环境直接安装:pip install facebook-wda
-
2.安装iTunes:
原因:Itunes里面有usbmux驱动。安装成功后,连上iphone即可。
下载安装Windows 版 iTunes:https://support.apple.com/zh-cn/HT210384
解释说明:usbmuxd是苹果提供的一个服务,用于USB与TCP协议之间的转换,iTunes和Xcode之间就会用到这个服务。对于MAC来说,直接通过xcode运行调用XCUITest API发送指令,该指令通过usbmuxd发送给USB连接的手机。win想要模拟xcode发送数据给usb设备就需要用到iTunes里面的usbmux驱动。
- 3.tidevice
原理分析:
tidevice是阿里开源的一个基于Python的IOS自动化工具,通过逆向IOS通信协议,模拟xcodebuild与手机通信,向手机发送指令启动WDA。完全脱离MAC电脑执行自动化指令。
tidevice通过usbmuxd与手机通信启动WDA,通过建立一个TCP连接到usbmuxd的/var/run/usbmuxd TCP端口,然后usbmuxd将请求发送到USB连接的ios上。
安装命令:pip install “tidevice[openssl]”
tidevice主要用于启动WDA:tidevice --trace xctest
或:tidevice -u [设备 udid] wdaproxy -B [wda 的 bundle Id] --port 8100
- UDID( Unique Device Identifier)是iOS设备的唯一识别码,可以使用tidevice list命令查看。
- Bundle ID(Bundle identifier)为应用 ID,是iOS应用的唯一标识。是你编译WDA应用设置的名称,可通过tidevice applist命令查看。
tidevice:官方了解更多
四、WDA的使用
初始化
import wda
# 展示请求和响应信息
wda.DEBUG=True #打开debug日志展示HTTP请求和响应信息
wda.HTTP_TIMEOUT=180
wda.DEVICE_WAIT_TIMEOUT=180
创建一个客户端
连接设备并创建客户端
c=wda.Client()
不传地址的时候,自动读取环境变量device_url。如果没有设置环境变量,就默认是:http://local:8100
#通过usb先连接手机
c=wda.USBClient()
#默认安静的等待120s无进度输出
c.wait_ready(timeout=120,noprint=True)
# 指定设备 udid 和WDA 端口号
# c = wda.USBClient("5ea095ddd531f39af9ed7f5b0790e2eb7f8ad388", port=8100)
# 通过DEVICE_URL访问
# c = wda.Client("http+usbmux://{udid}:8100".format(udid="5ea095ddd531f39af9ed7f5b0790e2eb7f8ad388"))
c = wda.USBClient("5ea095ddd531f39af9ed7f5b0790e2eb7f8ad388", port=8100, wda_bundle_id="com.facebook.WebDriverAgent.test2.xctrunner") # 1.2.0 引入 wda_bundle_id 参数
wda.client()会自动启用WDA应用。
设备操作
按home键
c.home() 也可以写成c.press("home")
c.healthcheck()
# c.source()
锁屏
# c.lock()
获取锁屏状态:c.locked()
解屏
# c.unlock()
调大音量
c.press("volumeUp")
调小音量
c.press("volumeDown")
按音量+键持续2s
c.press_duration("volumeUp",2)
打开app
s=c.session("com.apple.Health")
s.close()
c.session().app_activate("com.lockin.loock")
关闭app
c.session().app_terminate("com.lockin.loock")
#获取app的状态
STA=c.session().app_state("com.lockin.loock")
print(STA)
{'value': 3, 'sessionId': 'CB3D24CE-9690-413C-9C97-0B9BACB1DE7F', 'status': 0}
# value = 1是已关闭;2是后台运行;3是表示前台运行;4运行中
查看设备状态信息
print(c.status())
获取应用信息:
print(c.app_current())
{'processArguments': {'env': {}, 'args': []}, 'name': '', 'pid': 33, 'bundleId': 'com.apple.springboard'}
获取设备信息:
print(c.device_info())
{'timeZone': 'GMT+0800', 'currentLocale': 'zh_CN', 'model': 'iPhone', 'uuid': '5DDE5F99-4067-442C-B78D-85329D22C1F2', 'thermalState': 0, 'userInterfaceIdiom': 0, 'userInterfaceStyle': 'light', 'name': 'iPhone', 'isSimulator': False}
查看分辨率:
print(c.window_size())
元素定位
基本选择器
通过id,className,name,value,label等多个属性,以及属性组合定位。
s(name="KB/s")
s(nameContains="KB/s")
s(name="KB/s",className="xxx")
子元素定位
s(name="KB/s").child(name="通知").exists
定位到多个元素的处理
返回的是一个数组,通过下标获取元素
elets=c(className="XCUIElementTypeOther").find_elements()
print(elets[0])
可以通过index来直接选择匹配元素
ele=c(className="XCUIElementTypeOther",index=2)
或ele=c(className="XCUIElementTypeOther")[2]
Xpath定位
ele=c(xpath="//*[@name='设置']")
或c.xpath(”xxx“)
元素方法使用
检查元素是否存在
c(className="scd").exists
return true or false
获取元素属性信息
ele=c(className="XCUIElementTypeOther").get(timeout=5)
ele.visible
ele.value
ele.text
元素操作方法
点击
c(name="智能").click()
5s内反复检查,元素出现就执行点击操作
c(name="智能").click_exists(5)
c(name="智能").get(timeout=5).tap()
c(name="智能").tap()
长按2s
c(name="智能").tap_hold(2)
点击像素坐标
c.tap(390,293)
c.click(232,434)
双击
c.double_tap(234,564)
文本输入
获取元素位置
ele=c(name="智能").get()
#打开百度,执行文本操作
c.open_url("http://www.baidu.com")
time.sleep(2)
c(nameContains="输入").click()
ele=c(nameContains="输入").get()
print(ele)
# 输入文本
ele.set_text("HAHA")
time.sleep(3)
# 删除文本
c.xpath('//SearchField').set_text("\b\b\n")
time.sleep(1)
# 清除文本
c.xpath('//SearchField').clear_text()
元素等待
wait()方法:等待元素出现
#等待查找到元素就点击
s(name="实时视频").click_exists(5)
# if s(name="实时视频").click_exists(5):
# s(name="实时视频").click()
# if s(nameContains="KB/s").exists:
# 等待元素出现
if s(nameMatches="KB/s").wait(10):
t2=time.time()
loadingTime=t2-t1
print(loadingTime)
print("进入直播了")
else:
print("“直播失败了?")
wait_gone()
#等待元素消失
s(name="KB/s").wait_gone(5)
Alert操作
对弹窗处理
# 弹窗处理
if s.alert.exists:
con_text=s.alert.text
s.alert.accept()
s.alert.dismiss()
s.alert.click("取消")
#等待弹窗出现
s.alert.wait()
# 监控到alert出现后操作
with s.alert.watch_and_click("确定"):
s(label="Setting").click()
滑动swipe
c.swipe_left()
c.swipe_right()
c.swipe_up()
c.swipe_down()
# 从坐标A(x1,y1)滑到坐标B(x2,y2)
c.swipe(x1,y1,x2,y2,duration=1)
截图
c.screenshot().save("2.jpg")
from PIL import Image
# ROTATE_90 决定手机的角度,可以270旋转
c.screenshot().transpose(Image.ROTATE_90).save("hengping.jpg")
c.press_duration("snapshot", 0.1)
四、 FAQ
1、若定位不到元素,一定要检查是否手机上有多个同样包名的APP
2、若一段时间出现ios上的wda失效,需要重新在mac系统下编译运行,重装一下WDA