STF STF 集成 iOS 之源码分析

琉丶言 · June 25, 2019 · Last by 蓝蓝 replied at July 05, 2019 · 1737 hits

目前,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,可以找源码作者答疑。

STF架构源码分析:

如果你有node项目部署经验应该能够很容易看懂下面的源码目录,源码目录详解:
/.tx #集成翻译平台Transifex的相关配置,用于语言翻译
/bin #启动文件,调用的是lib/cli.js
/docker #Docker的相关配置
/lib #后端
/res #前端
/doc #文档说明,包含VNC,部署,API
/test #状态检测
/vendor #安装到手机上的应用和服务,包括minirev,minitouch,STFService


前端res
主要为Service服务和View页面两大部分
/app #前端web

  • /components/stf #服务组件,用于与后端通讯
  • /control-panes #页面,设备控制
  • /device-list #页面,设备列表
  • /docs #页面,帮助
  • /layout #页面,布局
  • /menu #页面,菜单
  • /setting #页面,设置
  • /terminal #页面,终端样式
  • /user #页面,用户,暂未完成
  • /views #页面,主视图
    /auth #登录认证
  • /ladp #页面,LADP认证
  • /mock #页面,默认验证 /common #其他
  • /lang #语言包
  • /logo #页面,图标
  • /status #页面,脚本 /test #登录,跳转 /web_modules #样式

后端lib
/cli #引入后端功能模块的index.js文件
/db #数据操作相关文件

/units #核心代码,用于功能实现

  • /api #主要的RESTful APIs
  • /app #提供主要HTTP服务,处理所有静态资源,包括图片,脚本和样式表
  • /auth #授权验证,Mock auth,OAuth 2.0,LDAP,SAML 2.0
  • /device #设备功能的具体实现.设备端底包,服务和STFservice.apk的安装
  • /log #将设备事件log存储至数据库
  • /notify #用于推送通知或到你的环境
  • /pooxy #数据库代理相关
  • /processer #设备和app之间的桥,几乎所有通讯都经过它
  • /provider #设备提供和发收命令
  • /reaper #接收心跳,处理设备异常断连
  • /storage #截图,图像存储和调整,操作apk
  • /triproxy #用于接受和处理来自app和设备端的请求
  • /websocket #用于客户端js和服务端(ZeroMQ,Protobuf )的通讯,所有action均由此发送 /util #内部方法 /wire #队列,路由,流相关方法

ios云真机模块:

为了不影响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云真机模块之设备发现和屏幕传输:

下面主要讲解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 之远程控制

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

共收到 11 条回复 时间 点赞

沙发,狂顶!

我第二个顶,点赞

赞!好文!

6666,不愧是大佬,很有深度

感谢分享技术干货,深度好文

请问支持的ios版本有限制吗?

@liuyan 能否放个video或者gif看下效果呢?

luis 回复

可以来QQ群:168170256 里看,我上传了mp4

琉丶言 #10 · June 25, 2019 作者
Bob 回复

ios10 以上效果好

👍 牛掰,看MP4好流畅,为咋我装完,用着很不流畅😭 😭

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up