目前,iOS 的设备云真机集群工具在国内外普遍处于收费模式,国内的 ios 远程真机技术基本都掌握在互联网巨头手里(如 BAT),个人感觉这个并不是一个好的现象,需要一些力量来打破现状。然而开源社区的一些 ios 远程真机也做的差强人意,其中如 ios-remote 采用 ios-minicap,致命的缺点是一台 mac 只能带一台手机,这么高的成本导致不适合做二次开发和推广。atxserver2 里面提供 ios-proivder 由于作者 codeskybule 工作太忙,做的不是特别精细,其 ios 云真机的流畅度和远程操作性还有提升空间。macaca 的 ios 功能没使用过,但是曾经用 macaca 和 uirecorder 封装过 web 平台针对 andriod app 的录制回放平台,感觉其代码水平应该是阿里的实习生写的,其功能并不好用(实话实说),其他开源 ios 云真机平台在这就不一一点评了,有点偏题了,下面进入正题。
由于 appium 1.9 以后在 WebDriverAgent 加入了一个 mjpegServer,通过私有 api 的方式获取屏幕截图(WDA 编译能不能通过跟 Xcode 有关,Xcode10.2 及以上私有 api 被删掉,所以请选择 Xcode10.1 及以下)。真机实测,在大屏幕手机上,帧率可达到 25 帧左右,而在小屏幕手机上,可达到 40fps 以上,且延时在 100ms 左右。这个帧率和延时肉眼基本看不出差异了。
综上,我们选择 appium 的 WebDriverAgent 来提供截图服务,WDA 默认监听 9100 端口,我们使用 iproxy 将手机的 9100 端口映射到本机的端口,这样手机和主机之间的屏幕传输走 usb,不会因为手机的网络导致延时和卡顿。@mrx102 虎牙哥之前的三篇帖子已经分析讲得很清楚了,而且也已经开源了,项目地址:https://github.com/mrx1203/stf.git https://github.com/mrx1203/WebDriverAgent.git。
该项目是完全结合了开源框架 OpenSTF,非常容易上手,适合做二次开发和商业化的云真机平台,其 ios 云真机画面流畅且远程操作性已经算是国内开源 ios 云真机中最好的(实测比美国公司 HeadSpin 的内部最新 ios 云真机技术流畅度稍微差一点点),而且一台 mac 可以带多台 iphone 设备(1 拖 N),真正意义上的终结了国内外 ios 远程真机技术被封闭垄断的现象。如果大家有兴趣搭建部署的话,可以加入 STF 技术交流 QQ 群:168170256,可以找源码作者答疑。
如果你有 node 项目部署经验应该能够很容易看懂下面的源码目录,源码目录详解:
/.tx # 集成翻译平台 Transifex 的相关配置,用于语言翻译
/bin # 启动文件,调用的是 lib/cli.js
/docker #Docker 的相关配置
/lib # 后端
/res # 前端
/doc # 文档说明,包含 VNC,部署,API
/test # 状态检测
/vendor # 安装到手机上的应用和服务,包括 minirev,minitouch,STFService
前端 res
主要为 Service 服务和 View 页面两大部分
/app # 前端 web
后端 lib
/cli # 引入后端功能模块的 index.js 文件
/db # 数据操作相关文件
/units # 核心代码,用于功能实现
为了不影响 STF 原来的目录,和原来的架构保持一致,ios 云真机模块主要在后端 lib 的/cli 下创建新的 ios-device、ios-provider、local 文件夹和/units 下重新创建了与/cli 对应的功能模块 ios-device、ios-provider 文件夹,用于来实现 ios 设备接入 STF 前端(STF 前端无需修改)。
首先,/cli 下 local 文件夹(stf local 本地方式启动 STF 服务,用于调试),参考原来的 index.js 增加定义了 ios 云真机需要用到的 wda 的端口、wda 相关启动路径和 ios-provider
同理/cli 下 ios-device 引入 units/ios-device 的功能模块
同理/cli 下 ios-provider 引入 units/ios-provider 的功能模块
这里传入的参数一定要保持正确,否则,很容易导致 units/ios-provider 模块 options.fork 方法参数识别不正确,请注意的参数里面增加了 wda-port、wda-path、type 的字段,type 这个字段是用来描述 ios 设备连接状态:离线、已授权、未授权、连接中等。真机设备就绪后可以为 device 状态,模拟器设备可以为 emulator 状态,后面设备连接成功前端收到设备信息后会在前端对应显示空闲或者繁忙。
其次,对应的功能模块 units/ios-porvider,去掉了 minicap 和 adb 相关的内容,里面主要定义了 porvider 里面 idevice.js 文件发现的所有 ios 设备的存储 lists 和两个状态 ready[ ] 和 waiting[ ] 的设备列表,当 cli/ios-provider 模块 options.fork 和 ios 设备子进程加载成功后,收到设备进程的 ready 消息会被添加到 ready 列表,同时从 waiting 列表移除。接下来最关键就是下面这段代码
调用链如下:匿名函数发送 DeviceIntroductionMessage 消息返回 register-->register.then(()=>check())-->work-->spawn-->开启 device 子进程
最后,上面提到了设备连接成功后会向前端发送设备信息,在设备开始连接的时候,ios 设备子进程会加载很多依赖的模块,打开文件/stf/lib/units/ios-device/index.js
其中 solo.js 这个依赖文件 :有两个作用 1:通过 wire.uitl 传递 DeviceIdentityMessage 设备信息:、2:通知前端 DeviceReadyMessage 是否就绪的重要代码。
进一步解析,DeviceIdentityMessage 内封装的设备信息来源于哪里,可以发现 solo 文件中引用了 identity 模块,打开/stf/lib/units/ios-device/plugins/util/identity.js 文件
里面包括一个用于获取设备的基础信息 properties,一个用于获取设备的屏幕信息 display,一个包括设备的硬件网络等信息 phone
display 使用采用 libimobiledevice 工具集下 idevicescreenshot 获取
phone 和 properities 采用 libimobiledevice 工具集下的 ideviceinfo -u 获取
具体获取方式可以查看这两个对应的 display.js 和 phone.js 文件
下面主要讲解 ios 设备发现和 mjpeg 视频流传输及解析部分,对于熟悉 STF 的同学,肯定会觉得这两个模块才算是精华部分,下面着重讲解下这两个部分
云真机设备发现模块主要依靠:\lib\units\ios-device\plugins\idevice.js 这个文件,这个文件定义了发现真机设备和模拟设备的,包括增加设备、删除设备和更新设备。使用的工具还是采用 libimobiledevice 工具集下 idevice_id -l
然后,怎么获取设备的视频图像呢,打开\lib\units\ios-device\plugins\screen\stream.js,这个文件也是复用了 STF 之前的 stream.js 插件,不过去掉了 adb 和 minicap 相关的内容,这个文件的作用是把视频图像(appium wda Mjpeg server 默认 9100 端口出来的图像帧)经过解析(this.parser = new FrameParser())后以一定帧率通过 websocket 传到前端显示
对 wda 源码修改和数据调优相关功能分别可以看 wda OC 源码和@mrx102 虎牙哥的 STF 集成 iOS 之远程控制
远程操作使用 WDA 来驱动,只是 WDA 中的点击/滑动是与控件关联的,而我们的使用场景无需关联控件,直接通过坐标来实现,重写或者增加了 WDA 的点击和滑动的接口。
打开文件 stf/lib/units/device/plugins/touch/index.js,可以看到对应的坐标、按键等处理模块
除了基本 ios 设备操作,还有屏幕旋转、ipa 上传,ios 设备调试日志功能、远程调试等相关的代码功能在这里就不一一分析了,有兴趣自行研究源码或者可以来群里讨论。
附上一张截图:
BUG:目前来说唯一发现一个小问题就是采用 sharp 工具来压缩 frame 图像帧后 toBuffer(), 会在后台报一个某些 frame 压缩后不是 buffer 而是 obeject 对象的警告错误,但是不影响正常使用,有强迫症的同学,这里可以使用 gm 工具代替,但是 gm 的压缩工具性能不如 sharp,所以还是最高使用 sharp。
应楼下同学要求,最后再放一个演示视频:
gif 效果不好,可以来 STF 技术交流群观看 mp4 演示效果。
https://testerhome.com/topics/19548
https://testerhome.com/topics/13680