iOS automated testing tool-tidevice

During the iOS testing process, you often need to check the device udid, check the package name, install and uninstall applications, obtain device screenshots, obtain performance data and other operations. Android has a wealth of adb commands that you can use. iOS's tidevice tool is similar to Android's adb, can provide these functions;

There has been no tool that can directly obtain iOS performance data. Tidevice can easily obtain performance data;

In addition, the execution of iOS automation has always relied on the mac system. The main reason is that xcode is required to compile and install wda (WebDriverAgent) into the ios device, and the tested application can be operated through wda. However, the Windows system cannot run Xcode, so it cannot run iOS automated testing; tidevice also solves this problem.

1. Introduction

Tidevice is Alibaba's open source iOS automated testing tool. It can provide functions such as taking screenshots, obtaining mobile phone information, installing and uninstalling IPA packages, starting and stopping applications based on bundle ID, obtaining specified application performance data, and simulating xcode to run xctest. The range of supported iOS phones is 9-16.

https://github.com/alibaba/taobao-iphone-device

2. Principle of tidevice

usbmux communication protocol: realizes communication between Mac/Windows/Linux and iOS device services

Mac side: usbmuxd is a service of Apple. This service is mainly used to implement multiple TCP connections on the USB protocol. It abstracts USB communication into TCP communication and establishes a TCP connection to the /var/run/usbmuxd TCP port of usbmuxd. usbmuxd then sends the request to the USB-connected iPhone. Apple's iTunes and Xcode all use this service directly or indirectly.

Linux/Windows side: There is no usbmux itself, but there are implementations of open source projects, which can be used/referenced directly.

Windows also relies on two services, AppleApplicationSupport and AppleMobileDeviceSupport. You can install the corresponding services by installing the Itunes environment.

usbmux itself is a socket. Through interception, cracking and other means, combined with the results of the open source industry, it is simulated with python, thus realizing all the functions of current tools.

3. Installation and configuration

1. Depends on the environment

python3.6 or higher

2.tidevice installation

pip3 install -U "tidevice[openssl]" 

If there are multiple python3 versions on your computer, it is best to specify the python version to install:

电脑上有python3.9和python3.11,想基于python3.9使用tidevice,所以指定python3.9版本
python3.9 -m pip install -U "tidevice[openssl]" 

Verify successful installation:

$ tidevice version

tidevice version 0.9.12

3. usbmux installation

4. Introduction to commonly used commands

Tidevice is a python project. All cmds supported by tidevice are implemented in tidevice.__main__, and the functions can be re-encapsulated.

#查看更多功能
$ 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. List connected devices

$ 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. Application management

(1) Install the application

#安装应用
$ tidevice install example.ipa

(2) Specify device installation

#指定设备安装
$ tidevice --udid $UDID install  https://example.org/example.ipa

(3) Uninstall the application

#卸载应用
$ tidevice uninstall 包名

Uninstalling 'com.XXX.XXX'
- RemovingApplication (50%)
- GeneratingApplicationMap (90%)
Complete

(4) For movement

#启动应用
$ tidevice launch bundleid

PID: 675

(5) Stop application

#停止应用
$ tidevice kill bundleid

Kill pid: 675

(6) View installed applications

#查看已安装的应用
$ tidevice applist

com.alipay.iphoneclient 支付宝 10.3.70

(7) View running applications

#查看运行中的应用
$ 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) View application information

$ tidevice appinfo com.example.demo

3. View device information

$ 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.Other commonly used

(1) Restart the phone

# 重启
$ tidevice reboot

(2) Cut image

# 截图
$ tidevice screenshot xxx.png

(3) Exodus Nishishi

# 输出日志 same as idevicesyslog
$ tidevice syslog

5.Crash log operation

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

5. Performance data collection

Tidevice can use the command line or python script to obtain performance data.

1. Command line method

#命令详解
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 script method

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()

You can use pyecharts to automatically generate real-time performance collection reports.

Install 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')

Get memory data + overall drawing code:

import time
import tidevice
from tidevice._perf import DataType
import os

#折线图
from pyecharts.charts import Line
#为图表添加参数
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)
    # 处理数据,拿到内存数值,四舍五入到小数点后一位
    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')

Later, we will consider making the script more versatile and run it with command line + parameters (only the bundle ID needs to be changed).

6. Run wda

Currently, on Mac computers, wda can be started and run through appium, so the existing UI automation does not use tidevice to start wda; here is an introduction to how to implement iOS automation on Windows computers, for information only.

To run iOS automation on a Windows computer, the environments required include:

  1. python

  2. tidevice

  3. iTools

  4. appium v1.20.0 or higher

  5. A real iOS machine with WDA installed (first use xcode to install webdriveragent on the phone, or package wda into ipa and install it on the phone)

运行WebDriverAgent

Several issues that are already known:

  • WDA signed by operating enterprise certificates is not supported;

  • The data cable may cause the wda connection to be interrupted. Data cable used by the author (recommended): https://item.jd.com/44473991638.html

The wdaproxy command will call xctest and relay at the same time. In addition, when wda exits, xctest will be automatically restarted.

# 运行 XCTest 并在PC上监听8200端口转发到手机8100服务
$ tidevice wdaproxy -B com.facebook.wda.WebDriverAgent.Runner --port 8200

I encountered an error when running:

tidevice.exceptions.MuxError: [Errno No app matches] com.facebook.wda.WebDriverAgent.Runner

Use the tidevice applist command to check and find that the package name is com.facebook.WebDriverAgentRunner.xxxxx.xctrunner. You need to remember the name of the webdriveragentrunner installed on your device;

You can check it with tidevice applist, and then replace com.facebook.wda.WebDriverAgent.Runner in the command with the name of webdriveragentrunner on your device.

After startup, you can use Appium orfacebook-wda to run iOS automation.

facebook-wda sample code

import wda
c = wda.Client("http://localhost:8200")
print(c.info)

Appium requires the following configurations to be set:

  • automationName: Execution engine, iOS device needs to be set to XCUITest

  • webDriverAgentUrl: In the iOS running script, you need to configure webDriverAgentUrl to the appium driver so that appium's built-in process of starting wda with xcode will not be triggered. Otherwise Appium will look for xcode whenever this is triggered. Windows does not have xcode, so naturally it cannot run and an error message appears: Error: The usbmuxd socket at '/var/run/usbmuxd' does not exist or is not accessible

  • usePrebuiltWDA: Use already compiled WDA.

  • useXctestrunFile: Use Xctestrun file to start WDA. Since this function expects you to have already built the WDA project, it neither checks if you have the necessary dependencies to build nor WDA attempts to build the project. Default is false.

  • skipLogCapture: Skip starting to capture logs, the default is false.

"webDriverAgentUrl": "http://localhost:8200"
"usePrebuiltWDA": "false",
"useXctestrunFile": "false",
"skipLogCapture": "true",
"automationName": "XCUITest"

7. Tool comparison

tidevice

libimobiledevice

Introduction

Tidevice is Alibaba's open source iOS automated testing tool. It can provide functions such as taking screenshots, obtaining mobile phone information, installing and uninstalling IPA packages, starting and stopping applications based on bundle ID, obtaining specified application performance data, and simulating xcode to run xctest.

libimobiledevice is a library for communicating with Apple iOS devices using native protocols. Equivalent to Android's adb, it is used to obtain iOS device information. It is a necessary dependency library for appium to connect to iOS devices. Through this library, Mac OS can easily obtain iOS device information.

Same point

All can provide functions such as obtaining device information, uninstalling and installing applications.

Difference

Easy to install

Installation is cumbersome and prone to problems

Ability to start and stop applications based on bundle ID

Cannot start and stop applications based on bundle ID

Support mac/windows/linux system

Supports mac system, can be compiled and installed on Linux, does not support Windows system

Ability to obtain performance data

Performance data cannot be obtained directly

can start wda

Can't start wda

Guess you like

Origin blog.csdn.net/Vermouth_00/article/details/134862988