作者:imyzf

本文将为我们介绍自动化控制 iOS 模仿器的原理,为开发根据 iOS 模仿器的前端调试方案供应协助。

我们在开发 iOS App 内的前端页面时,有一个很大的痛点,页面无法运用 Safari Inspector 等东西调试。遇到了j I J i 2 F ? t问题,我们只能想方法加 vConsole,或许注入 WX , 1 Reinre,或许盲改,实在不可就找客户端同学手动打包调试,总之排查问题的路途非常困难。

在参阅了 RN 和 Weex 等跨平台结构的q H Z 开发东西后,我们发现= 0 n ! | n运用模仿器调试是处理该问题的很好方法,我们将前端页v | P e ^ q面放到模仿器的 App 中作业,苹果就不会对其有约束,允许我们运用 Safari Inspector 调试了。

Saf! W k 7 6 ari Inspector 是和 Chrome DeQ z L u f # R ` Wvtools 相? N ? 1 R J 6似的调试东西,由 Safari 浏览器自带,支撑以下功用:

构建根据 iOS 模仿器的前端调试方案
  • 检查页面元素
  • 检查网络恳求
  • 断点调试
  • 存储办理(Local Storage,Cookies 等)
  • ……

这些功用是 vConsole、Weinre 等+ A ; H H 0东西无法比拟的,可以协助我们快速定位问题。

根据这些原理,我们内部现已开发了一b ) t R款东西,部分功用视频可以点此预览。但因为该东西和内部事务耦合较深,现在暂无开源: ` l V ` X方案。

前提条件

介绍这套方案之前,我们需求了解一下方案的前提条件:

  • 装有 macN 6 4OS 和 Xcode 的电脑:因为苹果的约束,模仿器和 XcL o $ I q kode 只能在 macOS 上作业。Xcode 直接在 ApA * / Z ~ Z u p Store 中设备即可,非常简略,无需其他操作。
  • 为模仿器构建的 App 包:因为模仿器是根据 x86 架构的,需求客户端开发同学供应为模仿器构建的包,和在手机上设备的包会有所不同。
  • 支撑 URL SS O l C pcheme 引发的 App:承载前端页面的 App 有必要支撑用协议引发并翻开页面,才能用东西完结自动化,不然只能在 App 内手动点击相关链路翻开页面。

整体流程

构建根据 iOS 模仿器的前端调试方案

我们的模仿器调试方案整体流程如上图所示: D z

  1. 获取设备列表,供应给用户挑4 ~ / a 5 6 :
  2. 检查模仿器情况,假设没有发起,就发起该模仿器
  3. 检查是否h = Y l . 7 G 9设备对应的 App,假设没有设备,就下载设备包进行设备
  4. 发起 App,并翻开需求调试的页面
  5. 根据页面类型,运用对应的东西进行调试(例如 Safari Inspector)

核心东西

我们在完结本方案时,首要根据以下东西:

  • xcrun:Xcode 供应了一个指令行东西xcrk ! Jun对开发相关的功用进行控制,是一系列东西的集合。
  • simctl:xcrun供应了一个子指令simctl用于控制模仿器,供应了模仿器的发起、关闭、设备使用、翻开 URL 等功用。可以通过直接作业xcrul ` 4 8 E K 1 vn sims 3 b J Octl检查协助文档。
  • n. Z vode-simctl:由 Appium 供应的simctl 东西c M O 2 T ^的 JS 封6 z 1 装。因为前端的方案一般都是根据 node.js 开发的,所以可以运用 node-simctl 包更方便地控制2 n } 4 * ` R模仿器。不过f = a u , $因为node-simctl只供应了部分功用的封装,我们依然需求手动调用xcrun指令来完结更多功用。

模仿器控制

在本方案中,最重要的部分就是对模仿器的控制。

前期预备

用户通过 App Store 设备完 Xcode 后,第一次作业需求附和苹果的容许协议,然后自动设备一些组件,之后才可以正常运用。为了进步易用性,我们希望自动处理这个进程,而不是告诉用户,设备 Xcode 后要采取一些操作。

首要我们可以测验作业一次 xcrun simctl指令,假设用户第一次作业, L M } 5,错误信息中会提醒用户手动作业xcodebuild -license接受容许,所以我们 z ` Q v G可以在错误信息中& P m M ;查找xcodebuq w 5 ` N bild -license字符串,假设有找到,就自动动作业xcodebuild -license accept指令,协助用户自动接受容许。这儿要留意的是,作业该指令需求 root 权限,可以运用sudo-promptL C # a h x ^ ` !等包提权作业指令。

构建根据 iOS 模仿器的前端调试方案

获取设备列表

我们可以直b j 8 C e E V 2接运用 node-simctl 的getDevices()函数获取本地设备的所有设备列表,比调用Q T O指令行更方便,可以直接获取到一个政策,不需求自己解析,政策部分结构如下:

{
'13.4': [
{
sdk: '13.4'j D R,
dataPath: L 5 H'/Users/xx/Library/Developer/CoreSimH D R 3 P 9 h P dulator/Devices/xxx/data',
logPath: '/Users/xx/Library/Logs/xxx',
udid: 'C1AG } j $ w U W ( 5A97n H 9 8 = Q & M36-XXX-YYY-ZZZ-2A4A674B6B21T - L',
isAva! ( Qilable: true,
deviceTypeIdentifier: 'com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pr- n T 2 ho-Max',
state: 'Shv v l l ) n ] : 4utdown',
name: 'iPhone 11 Pro Max',
platform: 'iOc ? ? . 4 : Q WS'
}
]
]

这儿不只包含了 iPhone,还有 Apple Watch 和 Apple TV 等设备,我们可以遍历返回成果,通过nk K x N r 1 Qame字段进行过滤,因为一般我们只需求在 iPhone 中{ ,进行调试。

发起设备

首要我们要判别设备是否现已发起,我们可以通过 xcrL 7 vun simctl bootstatus ${deviceId}指令获取设备w J # j z F [ t情况(这儿的 deviceId 即上面获取设备列表得到的udid),可是假设设备没有发起,这个指令会一向等候,不会退出,所以我们可以通过这个特征,根据指令是否超时(例如 1000ms 未返回成果)来判别设备是否发起F F V @ @ 9

接下来,就可以c v n M b |直接用xcrun int d ~ & (struments -w ${deviceId}指令,发起对应的设备了。

代码示例:

let status = '';
try {
stat: e & * i x _ vus =1 ^ D $ ) @ o 2 execSync(
`xcrun simctl bootstah 0 x X  E g Ztus ${deviceID p =d}`,
{ timeout: 1000 }
){ k 5 V r h g @ a;
} catch (error) {
// 假设模仿器未发起,会一向_ P 4 5 h B Y ^ b等候,然后超时 kill,抛出一个 ETIMEDOUT 失常
if (error.code !== 'ETIMEDOUT') {
throw error
}
}
// 检查是否发起
if (status.indexOf('Device already booted') < 0) {
console.log('正在发起模仿器……')
execSync(`xcrun instruments -w ${deviceId}`)
}

3 | C n K w v置 App

模仿器的设备包是一个以4 G 4 V Z 3 G $ 0.app为结尾命名的文件夹,和 macOS 使用类似,而不是 iPh* R 0one 真机上设备运用的.w ; m 2ipa包。所以设备y : ; 5 f 2包需求先用zip等东西进行打包上传到服务器,设备前下载到本地解压,运用 node-simctl 的installApp()方法进行设备。

App 检查和发起

关于用户是否设备了 App,其实是在通过剖析引发 App 的错误信息来判别的。假设 App 未y $ 1 | F – v设备,会在引发的时分a # I X 6会报错,错误信息中包含了domain=NSOSStatusErrC _ O M L A 7orDomai { In字符串,表明 Ap? B [ cp 没有设备,这w b = k R ! c ; 个时分我们去调用上面的设备流程即可。

构建根据 iOS 模仿器的前端调试方案

整个X ~ W ) ( l K M N流程中最重要的一步是怎样将我们的页面在 App 中翻开,实际上很简略,只需求 Appr . [ ! R 自身支撑类似 cloudmusic://open?url=xxx这样v U K y t的 URL Scheme 即可。我们通过 node-simctl 的R : 8openUrl()方法直接调用 scheme,模仿器便会帮我们发起F _ / ` B d L相关的 App,然后需求 App 依. P U V据接收[ Z 4 ; s U 3到的 Scheme 参数,帮我们l H翻开需求调试的页面。

代码示例:B ; `

try {
await simctl.openUrl(deviceI/ R B @ * # wd, url)
} catch (error) {
// 没有设备 App,翻开协议会报 NSOSStatusErrorDH H z % 7 H s Lomain
if (error.message.i) Z X 9 & * / @ 5ndexOf('domain=NSOSStatusErrorDomain') >= 0) {
await simctl.installApp(deviceId, appPath)
await sy A R O 3imctl.openUrl(deviceId, url)
}Z & a ( t - ] else {
throw error
}
}

发起调试器

在模仿器中翻开调试页面今后,关于 RNC n @ H T 0 e ; 页面,我们可以用 React Native Debugger 等东西调试。关于 H5 页面,我们可以从 Safari 菜单中翻开 Inspector调试(假设没有“开发”菜单,请在 Safari 偏好设置 – 高级 – 选中在菜单栏中线显示“m X } S开发”菜单)。

构建根据 iOS 模仿器的前端调试方案

当然这一步也可以完结自动化% * e W y % 5 ,需求借助 Apple Script 查找 Safari 菜单中的关键字并模仿点击,有点杂乱,并且跟着系统升级或许会失效,可以参阅网上的一些评论。

方案扩展

至此,我们现已了解了怎样控制模仿器,完结最基本的功用,可是我们还可以对方案进行扩展完结,进步易用性。

接入 CI 服务

客户端会定期发布新版别,参加新的功用,所以我们也需求坚持调试用的包为较新版别。一般客户? u @ I e G~ 2 n j : O @ I M团队都会建立自己的 CI 服务(例如 Jet d J & ) – + s 4nkins)进行打包,所以我们可以进行接入,自动下载和设备最新的包。乃至我们可以拉取 CI 服务器上的包列表,完结设备前史版别,回归调试一些功用。

需求留意的是,客户端团队一般只针对 ARM 架构打包,~ : o + O所以需求在 CI 上新增 x86 构建政策,构建产品才能成功在模仿器上作业。

多 App 支撑

跟着公司事务规模的拓宽,我们或许需求在多个 App 内调试页面,通过指定以下两点,可以完结多 App 的适配:

  1. URj X J : k *L Scheme:经1 5 ? R ;过指定不同的 Scheme,可以在不同的 App 中翻开页面
  2. Bundle ID:类似com.netease.cloudmusic这样的字符串,是 Ap~ g Z _ + = zp 的仅d L [有标识,可以通过这个 ID 来进行 App 的发起、中止c ? b [ f I ^、卸载等操作

总结

到此为止,我们介绍了构建一套根据 iOS 模仿 l ) ( q v G ( i器的前端调试方案的基本原理,根据以上内容,我们` Z K , k y ^ i c可以结合 commander 和 inquirer 开宣布一套 CLI 东西,也可以结合 Electron 开发一套 GUI 东西,为开发提效。假设你. W x * h i有更多的想法或许相关阅历,也欢迎在评论区与我们交流~

本文发布自 网易云音) – 3 E W / B乐前端团队,文章, O j L * H未经授权阻止任何形式的转载。我们一向在招人,假设你刚好预备换作业,又刚好q g – j喜欢云音乐,那就 参加我们!