在iOS测试过程中,经常会需要检察设备udid、检察包名,安装和卸载应用,获取设备截图,获取性能数据等操作,Android有丰富的adb命令可以使用,iOS的tidevice工具就雷同于Android的adb,可以提供这些功能;
一直以来也没有可以或许直接获取iOS性能数据的工具,tidevice可以方便的获取性能数据;
另外,一直以来iOS自动化的执行都依赖于mac体系,主要原因是需要xcode编译安装wda(WebDriverAgent)到ios设备中,通过wda实现对被测应用进行操作,而Windows体系无法运行Xcode,因此无法运行iOS自动化测试;tidevice也解决了这一题目。
一、简介
tidevice是阿里开源的iOS自动化测试工具,可以或许提供截图、获取手机信息、ipa包的安装和卸载、根据bundleID启动和停止应用、获取指定应用性能数据、模拟xcode运行xctest等功能。支持iOS手机的范围是9-16。
https://github.com/alibaba/taobao-iphone-device
二、tidevice的原理
usbmux通信协议:实现 Mac/Windows/Linux与 iOS设备服务间的通信
Mac端:usbmuxd 是苹果的一个服务,这个服务主要用于在USB协议上实现多路TCP毗连,将USB通信抽象为TCP通信,通过建立一个TCP毗连到usbmuxd的/var/run/usbmuxd TCP端口,然后usbmuxd将请求发送到USB毗连的iPhone上。苹果的iTunes、Xcode,都直接或间接地用到了这个服务。
Linux / Windows端:本身是没有 usbmux的,不外都有开源项目标实现,可以直接使用/参考。
Windows 另外依赖 AppleApplicationSupport和AppleMobileDeviceSupport 两个服务,安装Itunes 环境即可安装对应服务。
usbmux 本身是socket套接字,通过截获、破解等手段,联合开源界的结果,用python 进行模拟,从而实现了当前工具已有的所有功能。
三、安装与配置
1.依赖环境
python3.6以上
2.tidevice安装
- pip3 install -U "tidevice[openssl]"
复制代码 如果电脑上有多个python3版本,最好指定python版本安装:
- 电脑上有python3.9和python3.11,想基于python3.9使用tidevice,所以指定python3.9版本
- python3.9 -m pip install -U "tidevice[openssl]"
复制代码 验证安装成功:
- $ tidevice version
- tidevice version 0.9.12
复制代码 3.usbmux安装
- Mac 自带:/var/run/usbmux
- Linux/Windows: 参考官方建议的 tidevice.exceptions.MuxError: socket unix:/var/run/usbmuxd unable to connect · Issue #7 · alibaba/tidevice · GitHub
四、常用命令简介
tidevice是python工程,tidevice 支持的所有cmd 都在tidevice.__main__中界说实现,可对功能重新封装。
- #查看更多功能
- $ tidevice -h
- usage: tidevice [-h] [-v] [-u UDID] [--socket SOCKET] [--trace]
- {version,list,info,date,sysinfo,appinfo,applist,battery,screenshot,install,uninstall,reboot,shutdown,parse,watch,wait-for-device,launch,energy,kill,ps,relay,xctest,wdaproxy,syslog,fsync,crashreport,dumpfps,developer,pair,unpair,perf,set-assistive-touch,savesslfile,test}
复制代码 1.列出毗连设备
- $ tidevice list
- UDID SerialNumber NAME MarketName ProductVersion ConnType
- e372ee5092535ad955329aac04c4xxxxx F2LV30FXXX00 iPhone7p iPhone 7 Plus 13.6.1 usb
复制代码- $ ticevice list --json
- [
- {
- "udid": "e372ee5092535ad955329aac04c450fb7xxxx",
- "serial": "F2LV30XXG00",
- "name": "iPhone7p",
- "market_name": "iPhone 7 Plus",
- "product_version": "13.6.1",
- "conn_type": "usb"
- }
- ]
复制代码 2.应用管理
(1)安装应用
- #安装应用
- $ tidevice install example.ipa
复制代码 (2)指定设备安装
- #指定设备安装
- $ tidevice --udid $UDID install https://example.org/example.ipa
复制代码 (3)卸载应用
- #卸载应用
- $ tidevice uninstall 包名
- Uninstalling 'com.XXX.XXX'
- - RemovingApplication (50%)
- - GeneratingApplicationMap (90%)
- Complete
复制代码 (4)启动应用
- #启动应用
- $ tidevice launch bundleid
- PID: 675
复制代码 (5)停止应用
- #停止应用
- $ tidevice kill bundleid
- Kill pid: 675
复制代码 (6)检察已安装的应用
- #查看已安装的应用
- $ tidevice applist
- com.alipay.iphoneclient 支付宝 10.3.70
复制代码 (7)检察运行中的应用
- #查看运行中的应用
- $ tidevice ps
- PID NAME BUNDLE_ID DISPLAY_NAME
- 733 Preferences com.apple.Preferences 设置
- 274 CoreAuthUI com.apple.CoreAuthUI 用户鉴定
- 185 Spotlight com.apple.Spotlight Siri搜索
- 416 InCallService com.apple.InCallService InCallService
- 247 AlipayWallet com.alipay.iphoneclient 支付宝
- 713 SafariViewService com.apple.SafariViewService SafariViewService
- 344 EscrowSecurityAlert
- 748 MobileSafari com.apple.mobilesafari Safari浏览器
- 756 iMessageAppsViewService com.apple.iMessageAppsViewService iMessageAppsViewService
- #以json格式输出
- $ tidevice ps --json
- [
- {
- "pid": 733,
- "name": "Preferences",
- "bundle_id": "com.apple.Preferences",
- "display_name": "设置"
- },
- {
- "pid": 274,
- "name": "CoreAuthUI",
- "bundle_id": "com.apple.CoreAuthUI",
- "display_name": "用户鉴定"
- },
- {
- "pid": 185,
- "name": "Spotlight",
- "bundle_id": "com.apple.Spotlight",
- "display_name": "Siri搜索"
- }
- ]
复制代码 (8)检察应用信息
- $ tidevice appinfo com.example.demo
复制代码 3.检察设备信息
- $ tidevice info
- MarketName: iPhone 7 Plus
- DeviceName: iPhone7p
- ProductVersion: 13.6.1
- ProductType: iPhone9,2
- # 查看设备电源信息
- $ tidevice info --domain com.apple.mobile.battery --json
- {
- "BatteryCurrentCapacity": 100,
- "BatteryIsCharging": false,
- "ExternalChargeCapable": true,
- "ExternalConnected": true,
- "FullyCharged": true,
- "GasGaugeCapability": true,
- "HasBattery": true
- }
复制代码 4.其他常用
(1)重启手机
(2)截图
- # 截图
- $ tidevice screenshot xxx.png
复制代码 (3)输出日志
- # 输出日志 same as idevicesyslog
- $ tidevice syslog
复制代码 5.瓦解日志操作
- usage: tidevice crashreport [-h] [--list] [--keep] [--clear] [output_directory]
- positional arguments:
- output_directory The output dir to save crash logs synced from device (default: None)
- optional arguments:
- -h, --help show this help message and exit
- --list list all crash files (default: False)
- --keep copy but do not remove crash reports from device (default: False)
- --clear clear crash files (default: False)
复制代码- $ tidevice crashreport --list
-
- [I 230614 16:42:39 _crash:23] List of crash logs
- `-- /
- |-- debugserver-2023-06-02-110906.ips
- |-- WeChat-2023-05-30-180918.ips
复制代码
五、性能数据采集
tidevice可以用命令行或者python脚本方式获取性能数据。
1.命令行方式
- #命令详解
- usage: tidevice perf [-h] -B BUNDLE_ID [-o PERFS]
- optional arguments:
- -h, --help show this help message and exit
- -B BUNDLE_ID, --bundle_id BUNDLE_ID
- app bundle id (default: None)
- -o PERFS cpu,memory,fps,network,screenshot. separate by ","
- (default: None)
复制代码- #获取所有性能数据
- $ tidevice perf -B bundleID
- fps {'fps': 0, 'value': 0, 'timestamp': 1686732621727}
- gpu {'device': 0, 'renderer': 0, 'tiler': 0, 'value': 0, 'timestamp': 1686732621819}
- screenshot {'value': <PIL.PngImagePlugin.PngImageFile image mode=RGB size=281x500 at 0x7FCC995CA110>, 'timestamp': 1686732622353}
- fps {'fps': 50, 'value': 50, 'timestamp': 1686732622739}
- gpu {'device': 0, 'renderer': 0, 'tiler': 0, 'value': 0, 'timestamp': 1686732622829}
复制代码- #获取某一性能指标的数据,eg:memory
- $ tidevice perf -B bundleID -o memory
- memory {'pid': 287, 'timestamp': 1686732591464, 'value': 236.6890106201172}
- memory {'pid': 287, 'timestamp': 1686732592332, 'value': 236.6890106201172}
- memory {'pid': 287, 'timestamp': 1686732593323, 'value': 236.6890106201172}
- memory {'pid': 287, 'timestamp': 1686732594332, 'value': 236.6108856201172}
- memory {'pid': 287, 'timestamp': 1686732595319, 'value': 236.5640106201172}
- memory {'pid': 287, 'timestamp': 1686732596327, 'value': 236.5796356201172}
- memory {'pid': 287, 'timestamp': 1686732597318, 'value': 236.5952606201172}
复制代码- # 功耗采集
- # 每一秒打印一行JSON,至于里面什么单位不太懂
- $ tidevice energy com.example.demo
- {"energy.overhead": -10.0, "kIDEGaugeSecondsSinceInitialQueryKey": 0, "energy.version": 1, "energy.networkning.overhead": 0, "energy.appstate.cost": 8, "energy.location.overhead": 0, "energy.thermalstate.cost": 0, "energy.networking.cost": 0, "energy.cost": -10.0, "energy.cpu.overhead": 0, "energy.appstate.overhead": 0, "energy.gpu.overhead": 0, "energy.inducedthermalstate.cost": -1}
复制代码 2.python脚本方式
- import time
- import tidevice
- from tidevice._perf import DataType
- t = tidevice.Device()
- # perf = tidevice.Performance(t,[DataType.CPU, DataType.MEMORY, DataType.NETWORK, DataType.FPS, DataType.PAGE, DataType.SCREENSHOT, DataType.GPU])
- perf = tidevice.Performance(t,DataType.MEMORY)
- def callback(_type:tidevice.DataType,value:dict):
- print(_type.value,value)
- perf.start('com.example.demo',callback = callback)
- time.sleep(60)
- perf.stop()
复制代码
可以用pyecharts自动天生及时的性能采集报告。
安装pyecharts
- pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pyecharts
复制代码- #绘图
- x = [i for i in range(len(d))]
- y = d
- print(x)
- print(y)
- #创建对象,可以添加一些参数
- line = Line(init_opts=options.InitOpts(width='800px',height='600px'))
- #添加x轴y轴数据,注意添加y轴数据的时候必须设置series_name参数,表示图例的名称
- line.add_xaxis(xaxis_data=x)
- line.add_yaxis(series_name='memory', y_axis=y, is_symbol_show=True, label_opts=options.LabelOpts(is_show=False),
- #is_symbol_show=True显示点,label_opts=opts.LabelOpts(is_show=False)不显示值
- #设置展示最大值最小值
- markpoint_opts=options.MarkPointOpts(
- data=[
- options.MarkPointItem(type_="max",name="最大值", symbol="pin", symbol_size=[70,50]),
- options.MarkPointItem(type_="min", name="最小值",symbol="pin", symbol_size=[70,50], itemstyle_opts={'color':'#3CB371'}),
- ]
- ),
- #设置展示平均值
- markline_opts=options.MarkLineOpts(
- data=[options.MarkLineItem(type_="average",name="平均值")]
- ))
- line.render()
- os.system('open render.html')
复制代码
获取内存数据+画图整体代码:
- import timeimport tidevicefrom tidevice._perf import DataTypeimport os#折线图from pyecharts.charts import Line#为图表添加参数from pyecharts import optionst = tidevice.Device()# perf = tidevice.Performance(t,[DataType.CPU, DataType.MEMORY, DataType.NETWORK, DataType.FPS, DataType.PAGE, DataType.SCREENSHOT, DataType.GPU])perf = tidevice.Performance(t,DataType.MEMORY)d = []def callback(_type:tidevice.DataType,value:dict): print(_type.value,value) # 处理惩罚数据,拿到内存数值,四舍五入到小数点后一位 mem = round(value['value'],1) print(mem) d.append(mem) # with open('memory.txt','a') as f: # f.writelines(value)perf.start('com.xxx.xxx',callback = callback)time.sleep(1800)perf.stop()# print(d)#绘图
- x = [i for i in range(len(d))]
- y = d
- print(x)
- print(y)
- #创建对象,可以添加一些参数
- line = Line(init_opts=options.InitOpts(width='800px',height='600px'))
- #添加x轴y轴数据,注意添加y轴数据的时候必须设置series_name参数,表示图例的名称
- line.add_xaxis(xaxis_data=x)
- line.add_yaxis(series_name='memory', y_axis=y, is_symbol_show=True, label_opts=options.LabelOpts(is_show=False),
- #is_symbol_show=True显示点,label_opts=opts.LabelOpts(is_show=False)不显示值
- #设置展示最大值最小值
- markpoint_opts=options.MarkPointOpts(
- data=[
- options.MarkPointItem(type_="max",name="最大值", symbol="pin", symbol_size=[70,50]),
- options.MarkPointItem(type_="min", name="最小值",symbol="pin", symbol_size=[70,50], itemstyle_opts={'color':'#3CB371'}),
- ]
- ),
- #设置展示平均值
- markline_opts=options.MarkLineOpts(
- data=[options.MarkLineItem(type_="average",name="平均值")]
- ))
- line.render()
- os.system('open render.html')
复制代码 后续考虑让脚本更通用,以命令行+参数(只需要更改bundleID)的方式运行。
六、运行wda
目前Mac电脑上,通过appium即可启动运行wda,以是现有的UI自动化不使用tidevice来启动wda;在此介绍Windows电脑上怎样实现iOS自动化,仅供相识。
在Windows电脑上运行iOS自动化,需要用到的环境包括:
- python
- tidevice
- iTools
- appium v1.20.0以上
- 已经安装WDA的iOS真机(先用xcode给手机装上webdriveragent,或者把wda打包成ipa装得手机上)
运行WebDriverAgent
目前已经知道的几个题目:
- 不支持运营企业证书署名的WDA;
- 数据线大概导致wda毗连中断。作者使用的数据线(推荐): https://item.jd.com/44473991638.html
wdaproxy这个指令会同时调用xctest和relay,另外当wda退出时,会自动重新启动xctest。
- # 运行 XCTest 并在PC上监听8200端口转发到手机8100服务
- $ tidevice wdaproxy -B com.facebook.wda.WebDriverAgent.Runner --port 8200
复制代码 运行时遇到报错:
tidevice.exceptions.MuxError: [Errno No app matches] com.facebook.wda.WebDriverAgent.Runner
使用tidevice applist命令检察,发现包名是com.facebook.WebDriverAgentRunner.xxxxx.xctrunner,需要记好自己设备上安装的webdriveragentrunner的名称;
可以用tidevice applist检察,然后把命令中com.facebook.wda.WebDriverAgent.Runner替换为自己设备上webdriveragentrunner的名称。
启动后就可以使用Appium或者facebook-wda来运行iOS自动化了。
facebook-wda 示例代码
- import wda
- c = wda.Client("http://localhost:8200")
- print(c.info)
复制代码 Appium需要下面几个配置需要设置一下:
- automationName:执行引擎,iOS设备需要设置为XCUITest
- webDriverAgentUrl:iOS运行脚本中,需要配置 webDriverAgentUrl 给 appium driver ,才会不触发 appium 内置的用 xcode 启动 wda 这个流程。否则只要触发这个,appium就会找 xcode 。windows 没有 xcode ,天然跑不下去从而出现报错Error: The usbmuxd socket at '/var/run/usbmuxd' does not exist or is not accessible
- usePrebuiltWDA:使用已经编译好的WDA。
- useXctestrunFile:使用Xctestrun文件启动WDA。由于此功能期望您已经构建了WDA项目,因此它既不会检查您是否具有须要的依赖关系来构建,WDA也不会实行构建项目。默认为false。
- skipLogCapture:跳过开始捕获日志,默认为false。
- "webDriverAgentUrl": "http://localhost:8200"
- "usePrebuiltWDA": "false",
- "useXctestrunFile": "false",
- "skipLogCapture": "true",
- "automationName": "XCUITest"
复制代码
七、工具对比
tidevice
libimobiledevice
简介
tidevice是阿里开源的iOS自动化测试工具,可以或许提供截图、获取手机信息、ipa包的安装和卸载、根据bundleID启动和停止应用、获取指定应用性能数据、模拟xcode运行xctest等功能。
libimobiledevice是一个使用原生协议与苹果iOS设备进行通信的库。相当于 Android 的 adb,用于获取iOS设备信息,是 appium 毗连 iOS 设备必需要的依赖库,通过这个库 Mac OS 可轻松得到 iOS 设备信息。
相同点
均可提供获取设备信息、卸载安装应用等功能。
差别点
安装便捷
安装较为麻烦,轻易有题目
可以或许根据bundle ID启动和停止应用
不能根据bundle ID启动和停止应用
支持mac/windows/linux体系
支持mac体系,Linux上可编译安装,不支持Windows体系
可以或许获取性能数据
不能直接获取性能数据
可以启动wda
不能启动wda
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |