在iOS測(cè)試過(guò)程中,經(jīng)常會(huì)需要查看設(shè)備udid、查看包名,安裝和卸載應(yīng)用,獲取設(shè)備截圖,獲取性能數(shù)據(jù)等操作,Android有豐富的adb命令可以使用,iOS的tidevice工具就類(lèi)似于Android的adb,可以提供這些功能;
一直以來(lái)也沒(méi)有能夠直接獲取iOS性能數(shù)據(jù)的工具,tidevice可以方便的獲取性能數(shù)據(jù);
另外,一直以來(lái)iOS自動(dòng)化的執(zhí)行都依賴(lài)于mac系統(tǒng),主要原因是需要xcode編譯安裝wda(WebDriverAgent)到ios設(shè)備中,通過(guò)wda實(shí)現(xiàn)對(duì)被測(cè)應(yīng)用進(jìn)行操作,而Windows系統(tǒng)無(wú)法運(yùn)行Xcode,因此無(wú)法運(yùn)行iOS自動(dòng)化測(cè)試;tidevice也解決了這一問(wèn)題。
一、簡(jiǎn)介
tidevice是阿里開(kāi)源的iOS自動(dòng)化測(cè)試工具,能夠提供截圖、獲取手機(jī)信息、ipa包的安裝和卸載、根據(jù)bundleID啟動(dòng)和停止應(yīng)用、獲取指定應(yīng)用性能數(shù)據(jù)、模擬xcode運(yùn)行xctest等功能。支持iOS手機(jī)的范圍是9-16。
https://github.com/alibaba/taobao-iphone-device
二、tidevice的原理
usbmux通信協(xié)議:實(shí)現(xiàn) Mac/Windows/Linux與 iOS設(shè)備服務(wù)間的通信
Mac端:usbmuxd 是蘋(píng)果的一個(gè)服務(wù),這個(gè)服務(wù)主要用于在USB協(xié)議上實(shí)現(xiàn)多路TCP連接,將USB通信抽象為T(mén)CP通信,通過(guò)建立一個(gè)TCP連接到usbmuxd的/var/run/usbmuxd TCP端口,然后usbmuxd將請(qǐng)求發(fā)送到USB連接的iPhone上。蘋(píng)果的iTunes、Xcode,都直接或間接地用到了這個(gè)服務(wù)。
Linux / Windows端:本身是沒(méi)有 usbmux的,不過(guò)都有開(kāi)源項(xiàng)目的實(shí)現(xiàn),可以直接使用/參考。
Windows 另外依賴(lài) AppleApplicationSupport和AppleMobileDeviceSupport 兩個(gè)服務(wù),安裝Itunes 環(huán)境即可安裝對(duì)應(yīng)服務(wù)。
usbmux 本身是socket套接字,通過(guò)截獲、破解等手段,結(jié)合開(kāi)源界的成果,用python 進(jìn)行模擬,從而實(shí)現(xiàn)了當(dāng)前工具已有的所有功能。
三、安裝與配置
1.依賴(lài)環(huán)境
python3.6以上
2.tidevice安裝
pip3 install -U "tidevice[openssl]"
如果電腦上有多個(gè)python3版本,最好指定python版本安裝:
電腦上有python3.9和python3.11,想基于python3.9使用tidevice,所以指定python3.9版本
python3.9 -m pip install -U "tidevice[openssl]"
驗(yàn)證安裝成功:
$ 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
四、常用命令簡(jiǎn)介
tidevice是python工程,tidevice 支持的所有cmd 都在tidevice.__main__中定義實(shí)現(xiàn),可對(duì)功能重新封裝。
#查看更多功能
$ 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.列出連接設(shè)備
$ 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.應(yīng)用管理
(1)安裝應(yīng)用
#安裝應(yīng)用
$ tidevice install example.ipa
(2)指定設(shè)備安裝
#指定設(shè)備安裝
$ tidevice --udid $UDID install https://example.org/example.ipa
(3)卸載應(yīng)用
#卸載應(yīng)用
$ tidevice uninstall 包名
Uninstalling 'com.XXX.XXX'
- RemovingApplication (50%)
- GeneratingApplicationMap (90%)
Complete
(4)啟動(dòng)應(yīng)用
#啟動(dòng)應(yīng)用
$ tidevice launch bundleid
PID: 675
(5)停止應(yīng)用
#停止應(yīng)用
$ tidevice kill bundleid
Kill pid: 675
(6)查看已安裝的應(yīng)用
#查看已安裝的應(yīng)用
$ tidevice applist
com.alipay.iphoneclient 支付寶 10.3.70
(7)查看運(yùn)行中的應(yīng)用
#查看運(yùn)行中的應(yīng)用
$ tidevice ps
PID NAME BUNDLE_ID DISPLAY_NAME
733 Preferences com.apple.Preferences 設(shè)置
274 CoreAuthUI com.apple.CoreAuthUI 用戶(hù)鑒定
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": "設(shè)置"
},
{
"pid": 274,
"name": "CoreAuthUI",
"bundle_id": "com.apple.CoreAuthUI",
"display_name": "用戶(hù)鑒定"
},
{
"pid": 185,
"name": "Spotlight",
"bundle_id": "com.apple.Spotlight",
"display_name": "Siri搜索"
}
]
(8)查看應(yīng)用信息
$ tidevice appinfo com.example.demo
3.查看設(shè)備信息
$ tidevice info
MarketName: iPhone 7 Plus
DeviceName: iPhone7p
ProductVersion: 13.6.1
ProductType: iPhone9,2
# 查看設(shè)備電源信息
$ tidevice info --domain com.apple.mobile.battery --json
{
"BatteryCurrentCapacity": 100,
"BatteryIsCharging": false,
"ExternalChargeCapable": true,
"ExternalConnected": true,
"FullyCharged": true,
"GasGaugeCapability": true,
"HasBattery": true
}
4.其他常用
(1)重啟手機(jī)
# 重啟
$ tidevice reboot
(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
五、性能數(shù)據(jù)采集
tidevice可以用命令行或者python腳本方式獲取性能數(shù)據(jù)。
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)
#獲取所有性能數(shù)據(jù)
$ 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}
#獲取某一性能指標(biāo)的數(shù)據(jù),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自動(dòng)生成實(shí)時(shí)的性能采集報(bào)告。
安裝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)
#創(chuàng)建對(duì)象,可以添加一些參數(shù)
line = Line(init_opts=options.InitOpts(width='800px',height='600px'))
#添加x軸y軸數(shù)據(jù),注意添加y軸數(shù)據(jù)的時(shí)候必須設(shè)置series_name參數(shù),表示圖例的名稱(chēng)
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顯示點(diǎn),label_opts=opts.LabelOpts(is_show=False)不顯示值
#設(shè)置展示最大值最小值
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'}),
]
),
#設(shè)置展示平均值
markline_opts=options.MarkLineOpts(
data=[options.MarkLineItem(type_="average",name="平均值")]
))
line.render()
os.system('open render.html')
獲取內(nèi)存數(shù)據(jù)+畫(huà)圖整體代碼:
import time
import tidevice
from tidevice._perf import DataType
import os
#折線圖
from pyecharts.charts import Line
#為圖表添加參數(shù)
from pyecharts import options
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)
d = []
def callback(_type:tidevice.DataType,value:dict):
print(_type.value,value)
# 處理數(shù)據(jù),拿到內(nèi)存數(shù)值,四舍五入到小數(shù)點(diǎn)后一位
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)
#創(chuàng)建對(duì)象,可以添加一些參數(shù)
line = Line(init_opts=options.InitOpts(width='800px',height='600px'))
#添加x軸y軸數(shù)據(jù),注意添加y軸數(shù)據(jù)的時(shí)候必須設(shè)置series_name參數(shù),表示圖例的名稱(chēng)
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顯示點(diǎn),label_opts=opts.LabelOpts(is_show=False)不顯示值
#設(shè)置展示最大值最小值
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'}),
]
),
#設(shè)置展示平均值
markline_opts=options.MarkLineOpts(
data=[options.MarkLineItem(type_="average",name="平均值")]
))
line.render()
os.system('open render.html')
后續(xù)考慮讓腳本更通用,以命令行+參數(shù)(只需要更改bundleID)的方式運(yùn)行。
六、運(yùn)行wda
目前Mac電腦上,通過(guò)appium即可啟動(dòng)運(yùn)行wda,所以現(xiàn)有的UI自動(dòng)化不使用tidevice來(lái)啟動(dòng)wda;在此介紹Windows電腦上如何實(shí)現(xiàn)iOS自動(dòng)化,僅供了解。
在Windows電腦上運(yùn)行iOS自動(dòng)化,需要用到的環(huán)境包括:
-
python
-
tidevice
-
iTools
-
appium v1.20.0以上
-
已經(jīng)安裝WDA的iOS真機(jī)(先用xcode給手機(jī)裝上webdriveragent,或者把wda打包成ipa裝到手機(jī)上)
運(yùn)行WebDriverAgent
目前已經(jīng)知道的幾個(gè)問(wèn)題:
-
不支持運(yùn)營(yíng)企業(yè)證書(shū)簽名的WDA;
-
數(shù)據(jù)線可能導(dǎo)致wda連接中斷。作者使用的數(shù)據(jù)線(推薦): https://item.jd.com/44473991638.html
wdaproxy這個(gè)指令會(huì)同時(shí)調(diào)用xctest和relay,另外當(dāng)wda退出時(shí),會(huì)自動(dòng)重新啟動(dòng)xctest。
# 運(yùn)行 XCTest 并在PC上監(jiān)聽(tīng)8200端口轉(zhuǎn)發(fā)到手機(jī)8100服務(wù)
$ tidevice wdaproxy -B com.facebook.wda.WebDriverAgent.Runner --port 8200
運(yùn)行時(shí)遇到報(bào)錯(cuò):
tidevice.exceptions.MuxError: [Errno No app matches] com.facebook.wda.WebDriverAgent.Runner
使用tidevice applist命令查看,發(fā)現(xiàn)包名是com.facebook.WebDriverAgentRunner.xxxxx.xctrunner,需要記好自己設(shè)備上安裝的webdriveragentrunner的名稱(chēng);
可以用tidevice applist查看,然后把命令中com.facebook.wda.WebDriverAgent.Runner替換為自己設(shè)備上webdriveragentrunner的名稱(chēng)。
啟動(dòng)后就可以使用Appium或者facebook-wda來(lái)運(yùn)行iOS自動(dòng)化了。
facebook-wda 示例代碼
import wda
c = wda.Client("http://localhost:8200")
print(c.info)
Appium需要下面幾個(gè)配置需要設(shè)置一下:
-
automationName:執(zhí)行引擎,iOS設(shè)備需要設(shè)置為XCUITest
-
webDriverAgentUrl:iOS運(yùn)行腳本中,需要配置 webDriverAgentUrl 給 appium driver ,才會(huì)不觸發(fā) appium 內(nèi)置的用 xcode 啟動(dòng) wda 這個(gè)流程。否則只要觸發(fā)這個(gè),appium就會(huì)找 xcode 。windows 沒(méi)有 xcode ,自然跑不下去從而出現(xiàn)報(bào)錯(cuò)Error: The usbmuxd socket at '/var/run/usbmuxd' does not exist or is not accessible
-
usePrebuiltWDA:使用已經(jīng)編譯好的WDA。
-
useXctestrunFile:使用Xctestrun文件啟動(dòng)WDA。由于此功能期望您已經(jīng)構(gòu)建了WDA項(xiàng)目,因此它既不會(huì)檢查您是否具有必要的依賴(lài)關(guān)系來(lái)構(gòu)建,WDA也不會(huì)嘗試構(gòu)建項(xiàng)目。默認(rèn)為false。
-
skipLogCapture:跳過(guò)開(kāi)始捕獲日志,默認(rèn)為false。
"webDriverAgentUrl": "http://localhost:8200"
"usePrebuiltWDA": "false",
"useXctestrunFile": "false",
"skipLogCapture": "true",
"automationName": "XCUITest"
七、工具對(duì)比
tidevice |
libimobiledevice |
|
---|---|---|
簡(jiǎn)介 |
tidevice是阿里開(kāi)源的iOS自動(dòng)化測(cè)試工具,能夠提供截圖、獲取手機(jī)信息、ipa包的安裝和卸載、根據(jù)bundleID啟動(dòng)和停止應(yīng)用、獲取指定應(yīng)用性能數(shù)據(jù)、模擬xcode運(yùn)行xctest等功能。 |
libimobiledevice是一個(gè)使用原生協(xié)議與蘋(píng)果iOS設(shè)備進(jìn)行通信的庫(kù)。相當(dāng)于 Android 的 adb,用于獲取iOS設(shè)備信息,是 appium 連接 iOS 設(shè)備必需要的依賴(lài)庫(kù),通過(guò)這個(gè)庫(kù) Mac OS 可輕松獲得 iOS 設(shè)備信息。 |
相同點(diǎn) |
均可提供獲取設(shè)備信息、卸載安裝應(yīng)用等功能。 |
|
差異點(diǎn) |
安裝便捷 |
安裝較為麻煩,容易有問(wèn)題 |
能夠根據(jù)bundle ID啟動(dòng)和停止應(yīng)用 |
不能根據(jù)bundle ID啟動(dòng)和停止應(yīng)用 |
|
支持mac/windows/linux系統(tǒng) |
支持mac系統(tǒng),Linux上可編譯安裝,不支持Windows系統(tǒng) |
|
能夠獲取性能數(shù)據(jù) |
不能直接獲取性能數(shù)據(jù) |
|
可以啟動(dòng)wda文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-814985.html |
不能啟動(dòng)wda文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-814985.html |
到了這里,關(guān)于iOS自動(dòng)化測(cè)試工具-tidevice的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!