非常感谢梦无矶大佬的分享,go-iOS 方案我们团队还在调研中,大家可以根据大佬的分享,先行部署实现 iOS17 与 iOS18 的测试方案。
文章转载于:https://mp.weixin.qq.com/s/UJhd3mFwh2jLliY7KJA05A,已获得作者授权
目录:
一、go-ios 安装部署启动
1、Windows 系统驱动下载
2、Windows 系统驱动部署
3、配置环境变量
二、构建 wda.ipa
方案一:通过 xcode 构建
方案二:通过命令构建 wda.ipa
可能遇到的问题及解决方案
三、IOS18 启动自动化测试
四、连接到 AirtestIDE
五、封装 IOS17+ 的启动方法总结
go-ios 的基本使用
之前写过 IOS17 打包 WebDriverAgent 构建 ipa 包安装到 ios16.7 及 ios17 以上设备结合 tidevice3 进行自动化测试,但那种方式发现在不同的设备上会有失败的概率,小版本号也会有一定影响,而且操作比较繁琐,失败率较高。
于是乎在 tidevice 作者的推荐下,尝试使用 go-ios 这个开源项目进行启动 wda 程序,发现稳定性很好,ios17 以上,包括 ios18(目前最新),均可以正常启动 wda,同时 Airtest 也可以通过 ubsmax 连接 IOS17 及 IOS18 设备进行控件树识别,进行自动化测试。
代码层面,目前 Airtest 启动 wda 是采用的 tidevice,所以需要自己改动源码或者重新封装 go-ios 的方式进行启动,Airtest 官方目前也在调研 go-ios,后续应该会出相应解决 ios17、ios18 启动 wda 的方案,本文也会提供封装源码。
项目地址:https://github.com/danielpaulus/go-ios
releases 包下载:https://github.com/danielpaulus/go-ios/releases
这个项目也可以使用如下命令进行安装:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
npm install -g go-ios
releases 包可以根据自己的系统进行下载:
我使用的是 windows,非 Windows 系统可以跳过这段,通过 README 教程查看,需要下载相关驱动。
npm install -g go-ios
can be used to get going. Runios --help
after the installation for details. For iOS 17+ devices you need to runsudo ios tunnel start
for go ios to work. This will start a tunnel daemon. To make this work on Windows, download the latest wintun.dll from herehttps://git.zx2c4.com/wintun
and copy it toC:/Windows/system32
翻译:
npm install -g go-ios
下载后可以进行运行。安装后运行ios --help
了解详细信息。对于 iOS 17+ 设备,您需要运行sudo ios tunnel start
才能使 go ios 正常工作。这将启动一个 tunnel 守护程序。要在 Windows 上执行此操作,请从此处下载最新的wintun.dll https://git.zx2c4.com/wintun
并将其复制到C:/Windows/system32
驱动网址 1:https://www.wintun.net/
驱动网址 2:https://git.zx2c4.com/wintun
1、把下载好的驱动文件进行解压缩,进入bin\amd64
(现在的 windows 系统电脑一般是 amd64),把wintun.dll
文件复制到C:/Windows/system32
根目录下。
Ubuntu\Linux 查看系统内核
使用uname -m
查看架构类型。
使用lscpu
获取详细的 CPU 信息。
查看/proc/cpuinfo
文件中的详细信息。
2、注意:是把 dll 文件放过去,不是整个文件夹放过去
1、如果是通过 npm -g 安装的就不需要进行这一步,如果是通过 release 包进行下载的,想要在全局使用 go-ios,则需要配置环境变量。
2、比如我下载后存放的路径是D:\P_Program\go-ios-win\ios.exe
3、打开我的电脑 -> 属性 -> 系统 -> 系统信息 -> 高级系统设置 -> 环境变量
4、点开环境变量 -> 系统变量 -> 找到变量为 path 的,双击进入 -> 新建 -> 输入D:\P_Program\go-ios-win\ios.exe
-> 确认
5、win+r 输入 cmd,打开控制台,输入 ios 验证是否配置成功,出现如下内容,代表环境变量配置成功。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
C:\Users>ios
Usage:
ios activate [options]
ios listen [options]
.....
这个在之前的文章有写,这里简单阐述一下步骤,一个是通过 xcode 构建直接安装到设备,一个是通过命令构建 wda.ipa,再把该 ipa 安装到设备。
设备部署构建环境:
Mac 电脑:macOS Sonoma 14.5
Xcode16:需要下载支持 ios18 的内容
Appium-WebDriverAgent:v8.9.2
1、进入 appium-webdriveragent 下载源码:https://github.com/appium/WebDriverAgent/releases
2、使用 xcode16 打开源码目录下的WebDriverAgent.xcodeproj文件,打开后,在左侧选择WebDriverAgentRunner,然后在 Signing & Capabilities
选项卡中,确保 Automatically manage signing
选项已勾选。
3、xcode16 不再像之前的版本一样需要选 ios 小版本,这里只需要勾选 ios 大版本即可,账号使用企业开发者账户签名,个人的只有七天有效期。
•
选择正确的团队(Team),这将确保 Xcode 使用正确的签名证书和配置文件。
4、Bundle identifier 需要更改一下,不重复就可以了,我是直接在后面加点后缀。
5、连接目标 ios 设备,product --> Destination --> 选择对应设备,如果显示设备没有准备好,插拔连接线,还是这样直接重启就可以恢复连接。
6、选择对应方案,Product --> Scheme -- > WebDriverAgentRunner
7、启动构建测试:Product --> Build For --> Testing
8、测试构建:Product --> Test
以上步骤成功标志是:
Xcode 控制台正常输出日志
显示 Build Succeeded
设备上安装上了 WebDriverAgentRunner-Runner
设备上显示 Automation Running 动态水印样式
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
# 1、xcode打开代码下的WebDriverAgent.xcodeproj项目,配置好团队唯一id等信息
$ xcodebuild build-for-testing -scheme WebDriverAgentRunner -sdk iphoneos -configuration Release -derivedDataPath /tmp/derivedDataPath
# 2、cd的目录和上条命令/tmp/derivedDataPath目录是一致的
$ cd /tmp/derivedDataPath
# 3、这个目录是连续的可以和上条命令一起 cd /tmp/derivedDataPath/Build/Products/Release-iphoneos
$ cd Build/Products/Release-iphoneos
# 4、在这个目录下创建一个Payload文件夹,并且把.app文件复制到Payload文件夹下
$ mkdir Payload && mv *.app Payload
# 5、用zip命令打包出来一个ipa
$ zip -r WDA.ipa Payload
# 6、把WDA.ipa安装到指定设备上
$ ios install WDA.ipa --udid=<udid>
打开访达,shift+command+g 在出现的窗口中输入/tmp,斜杆必须写,这样可以进去对应目录吧 WDA.ipa 拖出来。
安装示列:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios install --path=ios18-WDA.ipa --udid=00008110-00112DA90E07801E
使用方案一在进行构建时,可能会出现构建失败,或者在安装 ipa 的时候会出现中断报错,这是因为我们在新的设备上没有信任该开发者账号。(ios17 之前貌似不用)
安装报错示列:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
{"err":"your app is not properly signed for this device, check your codesigning and provisioningprofile. original error: 'ApplicationVerificationFailed' errorDescription:'Failed to verify code signature of /var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.XyWuva/extracted/Payload/WebDriverAgentRunner-Runner.app : 0xe8008015 (A valid provisioning profile for this executable was not found.)'","level":"fatal","msg":"failed writing","time":"2024-09-14T18:46:41+08:00"}
解决方案:打开设置 -> 通用 -> VPN 与设备管理 -> 信任开发者
1、ios17 以上需要通过 go-ios 启动隧道
以管理员启动终端运行如下命令,且不要关闭该界面。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios tunnel start
启动之后不要关闭,连接到 ios17 以上设备会自动帮你启动隧道。
2、设置 -> 开发者 -> 启动 UI 自动化勾上,(如果没有打开开发者: 【设置】-【隐私与安全性】 ,拉到底部,就可在“安全性”一栏看到开发者模式了。)
3、指定设备启动 WebDriverAgentRunner
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios runwda --udid=00008110-00112DA90E07801E --bundleid=com.facebook.WebDriverAgentRunnerxzz.xctrunner --testrunnerbundleid=com.facebook.WebDriverAgentRunnerxzz.xctrunner --xctestconfig=WebDriverAgentRunner.xctest
1、打开 AirtestIDE
2、通过远程 IOS 连接
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios:///http+usbmux://00008110-00112DA90E07801E
3、点击连接即可,下面是 IOS17.6.1 和 IOS18 使用 go-ios 启动 wda 后连接 AirtestIDE 的展示
IOS18
4、均可以正常连上,后续也使用代码进行测试了,可以正常运行自动化,测试连接设备代码如下(脚本不便展示):
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
from airtest.core.api import *
# ios18设备的udid
devices = '00008110-00112DA90E07801E'
auto_setup(__file__, devices=[f"ios:///http+usbmux://{devices}", ])
from poco.drivers.ios import iosPoco
dev = connect_device(f"iOS:///http+usbmux://{devices}")
poco_ios = iosPoco(device=dev)
Airtest 中的方法 start_app() 是封装的 tidevice,但 tidevice 是不支持 ios17 和 ios18,并且作者开了新的 tidevice3,并且推荐 go-ios,所以可以直接修改源码更换,也可以重新封装,这里我为了不影响 ios17 之前的设备运行,我采用重新封装的方法。封装代码如下:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
# -*- coding: utf-8 -*-
"""
@Time : 2024/9/13 17:57
@Email : Lvan826199@163.com
@公众号 : 梦无矶测开实录
@File : connect_ios17_or_higher.py
"""
__author__ = "梦无矶小仔"
import os
import subprocess
import time
from airtest.core.api import connect_device, device, sleep, auto_setup, click, text
from poco.drivers.ios import iosPoco
class IOS17HigherAutomation:
def __init__(self, wda_package_name, uuid, wda_ipa_path, log_dir='./ios'):
self.wda_package_name = wda_package_name
self.uuid = uuid
self.wda_ipa_path = wda_ipa_path
self.log_dir = log_dir
self.device = None
self.poco = None
self.width = None
self.height = None
def install_wda(self):
os.system(self.wda_ipa_path)
time.sleep(6)
def run_wda(self):
run_wda_command = [
'ios', 'runwda',
f'--bundleid={self.wda_package_name}',
f'--testrunnerbundleid={self.wda_package_name}',
'--xctestconfig=WebDriverAgentRunner.xctest'
]
subprocess.Popen(run_wda_command)
time.sleep(6)
def connect_device(self):
self.device = connect_device(f"ios:///http+usbmux://{self.uuid}")
self.poco = iosPoco(device=self.device)
dev = device()
self.width, self.height = dev.get_current_resolution()
auto_setup(logdir=self.log_dir, compress=3, devices=[f"ios:///http+usbmux://{self.uuid}"])
sleep(6)
def start_recording(self, fps=4, orientation=1):
self.device.start_recording(fps=fps, orientation=orientation)
def stop_recording(self):
self.device.stop_recording()
def start_app(self, app_package_name):
# # you need to kill the app firstly, and then start the app
# otherwith it would fail to open the app after you open the app more than 188 times
self._kill_app(app_package_name)
self._launch_app(app_package_name)
def _kill_app(self, app_package_name):
kill_app_command = ['ios', 'kill', app_package_name]
subprocess.run(kill_app_command, check=True)
def _launch_app(self, app_package_name):
launch_app_command = ['ios', 'launch', app_package_name]
subprocess.run(launch_app_command, check=True)
def search_in_app_store(self, search_text):
self.poco(nameMatches=".*search").click()
self.poco(nameMatches="AppStore.searchField").click()
text(search_text)
click([self.width * 0.5, self.height * 0.5])
def uninstall_wda(self):
os.system(f'tidevice uninstall {self.wda_package_name}')
def main():
WDA_PACKAGE_NAME = 'xxx'
UUID = 'xxx'
WDA_IPA_PATH = r'ios install C:\xxx\xxxx\xxxx\xxxxx\xxxxx\wda.ipa'
ios_automation = IOS17HigherAutomation(WDA_PACKAGE_NAME, UUID, WDA_IPA_PATH)
ios_automation.install_wda()
ios_automation.run_wda()
ios_automation.connect_device()
ios_automation.start_recording()
ios_automation.start_app("com.apple.AppStore")
ios_automation.search_in_app_store("原神")
ios_automation.stop_recording()
ios_automation.uninstall_wda()
if __name__ == "__main__":
main()
大家可以根据这个,封装符合自己业务的代码。
1、安装 go-ios
2、使用 xcode 安装 WebDriverAgentRunner
3、使用ios tunnel start
和ios runwda --udid=00008110-00112DA90E07801E --bundleid=com.xxxx.xctrunner --testrunnerbundleid=com.xxxx.xctrunner --xctestconfig=WebDriverAgentRunner.xctest
命令启动 WebDriverAgentRunner
4、远程连接 AirtestIDE
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios activate [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios listen [options]
--details
参数可以获取详细信息。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios list [options] [--details]
display
获取显示信息, lockdown
获取锁定状态信息。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios info [display | lockdown] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios image list [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios image mount [--path=<imagepath>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios image unmount [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios image auto [--basedir=<where_dev_images_are_stored>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios syslog [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios screenshot [options] [--output=<outfile>] [--stream] [--port=<port>]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios instruments notifications [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios crash ls [<pattern>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios crash cp <srcpattern> <target> [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios crash rm <cwd> <pattern> [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios devicename [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios date [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios timeformat (24h | 12h | toggle | get) [--force] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios devicestate list [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios devicestate enable <profileTypeId> <profileId> [options]
--force
参数强制执行。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios erase [--force] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios lang [--setlocale=<locale>] [--setlang=<newlang>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios mobilegestalt <key>... [--plist] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios diagnostics list [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios profile list [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios prepare [--skip-all] [--skip=<option>]... [--certfile=<cert_file_path>] [--orgname=<org_name>] [--locale] [--lang] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios prepare create-cert
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios prepare printskip
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios profile remove <profileName> [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios profile add <profileFile> [--p12file=<orgid>] [--password=<p12password>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios httpproxy <host> <port> [<user>] [<pass>] --p12file=<orgid> --password=<p12password> [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios httpproxy remove [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios pair [--p12file=<orgid>] [--password=<p12password>] [options]
--apps
参数可以仅列出应用进程。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios ps [--apps] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios ip [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios forward [options] <hostPort> <targetPort>
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios dproxy [--binary] [--mode=<all(default)|usbmuxd|utun>] [--iface=<iface>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios readpair [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios pcap [options] [--pid=<processID>] [--process=<processName>]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios install --path=<ipaOrAppFolder> [options]
•
卸载应用,需要提供应用的包名。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios uninstall <bundleID> [options]
--system
参数列出系统应用, --all
参数列出所有应用, --list
参数列出简短信息, --filesharing
参数列出支持文件共享的应用。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios apps [--system] [--all] [--list] [--filesharing] [options]
--wait
) 或杀死已有的应用实例 ( --kill-existing
)。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios launch <bundleID> [--wait] [--kill-existing] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios kill (<bundleID> | --pid=<processID> | --process=<processName>) [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios runtest [--bundle-id=<bundleid>] [--test-runner-bundle-id=<testrunnerbundleid>] [--xctest-config=<xctestconfig>] [--log-output=<file>] [--xctest] [--test-to-run=<tests>]... [--test-to-skip=<tests>]... [--env=<e>]... [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios runwda [--bundleid=<bundleid>] [--testrunnerbundleid=<testbundleid>] [--xctestconfig=<xctestconfig>] [--log-output=<file>] [--arg=<a>]... [--env=<e>]... [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios ax [--font=<fontSize>] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios debug [options] [--stop-at-entry] <app_path>
rm
)、列出目录树 ( tree
) 或创建目录 ( mkdir
)。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios fsync (rm [--r] | tree | mkdir) --path=<targetPath>
pull
) 或推送文件到设备 ( push
)。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios fsync (pull | push) --srcPath=<srcPath> --dstPath=<dstPath>
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios reboot [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios -h | --help
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios --version | version [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios setlocation [options] [--lat=<lat>] [--lon=<lon>]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios setlocationgpx [options] [--gpxfilepath=<gpxfilepath>]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios resetlocation [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios assistivetouch (enable | disable | toggle | get) [--force] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios voiceover (enable | disable | toggle | get) [--force] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios zoomtouch (enable | disable | toggle | get) [--force] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios diskspace [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios batterycheck [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios tunnel start [options] [--pair-record-path=<pairrecordpath>] [--userspace]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios tunnel ls [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios tunnel stopagent
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios devmode (enable | get) [--enable-post-restart] [options]
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
ios rsd ls [options]