>科技>>正文

【藏经阁】iOS多机远程控制技术

原标题:【藏经阁】iOS多机远程控制技术

引言

移动端多机远程控制技术,业界Android端已有解决方案,如开源的STF。然而,相对于Android的开源,iOS相关技术一直很封闭,可利用的技术资源匮乏,暂无有效iOS多机远程控制技术。已有的iOS远程控制技术要么受限于单机或者要么视频不流畅,本文解决已知问题,提出一种iOS多机远程控制解决思路,实现多机远程控制技术。

关键技术点分析

要实现远程控制,需要解决两个事情,一个是如何能驱动手机完成一系列点击、滑动、长按、输入text操作;另一个是如何远程看到手机屏幕的画面。也就是两个关键技术点:事件驱动技术和桌面获取技术。此外,除了实现以上功能点,在性能上,需要满足快速响应的需求:事件驱动需要毫秒级完成响应,视频传输需要满足1s 20帧以上的流畅度。只有这样,才能让远程控制尽可能的逼近真机使用的体验。

事件驱动技术

iOS的事件驱动本质上,是完成类似于iOS自动化中的驱动事件,所以从已有iOS自动化框架研究入手,调研已有框架(下图)发现,有两大派系:非侵入式和侵入式,即是否在被测app中植入“测试代码”辅助完成驱动动作。因为远程驱动是一个系统级的控制,而侵入式的自动化驱动,往往局限在app范围内的动作执行,所以我们选择非侵入式的。

我们把目标缩小到WedDriverAgentUIAutomationAppiumYnm3ktuneup_js这些框架上,分析这些框架的底层实现原理,无外乎分三种类别:

1、私有api,使用苹果未公开的api实现。

2xcode8之前的UIAutomation

3xcode8及以后xctestxcuitest

例如,Appiumtuneup_js底层分别使用的是webdriveragentuiautomation,而wda底层使用的是私有apixcuitest。因为xcode8后,苹果放弃了uiautomation的自动化框架,所以我们选择facebook开源的iOS自动化框架WedDriverAgent作为iOS驱动技术方案。

wda实现了后台常驻的webserver,接收http请求后使用私有api或者xcuitest实现事件的驱动,实际使用存在个别驱动事件耗时过长的问题,原因在于wda为了保证自动化框架稳定性,使用大量事件同步等待机制。而对于远程驱动技术,并不需要关心事件执行过程中的一致性状态维护工作,只关心事件快速触发、执行即可。

桌面获取技术

已知的iOS获取屏幕桌面,有三种方法(不考虑越狱情况),分别介绍如下。

方法1:通过Airplay Mirror

Airplay是苹果提供一种多媒体多屏互动技术,可以将音频、照片、视频以及屏幕从iOS设备或者Mac电脑上传输到同局域网的接收设备上。这里的airplay-mirror技术就是屏幕数据传输的技术,因为该技术属于苹果私有协议方案,数据传输进行了加密,目前只有少数商业产品逆向破解了协议栈。例如AirServer 、LonelyScreenReflector,还有国内的各种盒子,天猫盒子,小米盒子等。

方法2:通过AVFoundationCoreMediaIO库获取

首先,介绍通过mac自带软件获取手机屏幕的方法,自从苹果发布OS X Yosemite10.10.xiOS 8 以来,在QuickTime-Player屏幕录像中选择连接mac电脑的iphone手机即可获取手机屏幕的画面,操作如下图。

这个方法实际上是使用AVFoundationCoreMediaIO库函数实现的屏幕获取。例如,使用该方法实现屏幕获取的开源工具ios-minicap,我们查看其源码可以发现具体调用函数如下。

实际测试使用,该方法图像传输速度很快,几乎达到无延迟的流畅效果,但是存在多设备无法并行的限制,具体来讲,1mac只能同时对1ios设备连接生效,无法实现1n的使用场景。

方法3:通过idevicescreenshot

idevicescreenshot属于开源工具集的libimobiledevice的子集,可以在pc上对usb连接的ios设备进行截图,并将图片保存在pc本地,这种方式使用最简单但是效率较低,实际测试200-300ms左右完成1次截图,也就是1s只能完成3-5帧的视频传输速度。

综上所述:方法1的技术掌握在少数商业产品上,无法得知实现方案。方法2传输速度快,但是存在1mac无法并行支持多台iOS的限制,而实际应用场景是,为了节省成本,1mac需要挂多台ios设备实现部署远程控制集群。方法3传输效率低,1s只能3-5帧,无法满足基本的使用流程体验。所以,已知的屏幕获取技术都无法满足需求。

解决思路及实践

分析已有技术的不足,结合远程控制的使用场景,我们聚焦解决两个问题,1、如何具备快速的事件驱动能力,2、如何具备流畅的截屏传输能力。

首先,我们解决事件驱动问题,参考已有wda中事件驱动代码,去掉同步机制,加入XCEventGenerator.h私有api实现,使事件驱动响应更快。

1、点击事件

注释掉框架内同步等待逻辑,使点击事件更高效。

2、滑动&长按事件

滑动事件使用XCEventGenerator私有api实现。输入是起始、终止坐标。对于长按事件,可以通过将输入和输出置为相同坐标,并将forduration持续时间设置hold时长即可模拟长按操作。

3home键事件

注释掉同步代码。

4、字符输入事件

这里解释下,去掉这些同步操作对稳定性的影响,我们看下wda同步机制是怎样的,见下面代码,可以看到,是通过额外的异步逻辑来保证每个页面的快照一致性来实现的,而快照获取是个极为耗时的操作,所以对于远程控制来讲,这些一致性同步操作并不需要。

接着,我们需要完成获取截屏数据,使用wda提供的方法。这里优先使用[xcScreen valueForKeyPath:@"mainScreen.screenshot.PNGRepresentation"]方法,过时方法[[XCAXClient_iOSsharedClient] screenshotData]iOS新版本会出现crash,但是效率略高。实际使用xcScreen速度只是稍微慢于screenshotData私有api的方式,可以接受。截完图后,需要对图片进行压缩,否则多张M级别的原始图片即便万兆局域网传输耗时也是吃不消的,本方案将图像质量压缩到0.1,实测1张截屏50k左右(实际会根据桌面颜色复杂度而异),且该压缩比下目测清晰高,截图和局域网发送耗时30-50ms之间。

imageData =

UIImageJPEGRepresentation(img,0.1)

最后,为了进一步将事件驱动和截屏获取高效的组装运转起来,我们在wda中注入2socket子线程,分别负责实时接收外部事件指令完成驱动和实时的发送截屏数据。

因为截屏操作苹果公司限制该API必须在主UI线程完成,否则会报错,所以截屏操作之前需要将函数切换到主UI线程中。同时,将timer触发事件类型设置成NSRunLoopCommonModes,避免UI主线程中的动作事件干扰截屏操作。再把截屏的data扔回子线程完成网络发送。

综上如上图,我们在wda基础上,通过引入2个子线程,实现事件和视频流实时传输。在事件流中,通过引入更高效的XCEventGenerator私有api以及优化已有的wda中同步保护逻辑,实现事件高效驱动。在视频流中,通过0.001s间隔的timer,进行截图并发送。以上方案相对于已有的方案更高效,事件流节省了同步机制、视频流避免的本地iO的转发的时间损耗。

其他问题及解决

点击坐标尺寸换算

iphone手机型号很多,坐标转换需要自定义实现,这里需要注意的是,对截图进行逻辑坐标的换算才可以在客户端进行所见即所得精确的点击等操作,各个iOS设备型号的逻辑坐标如下。例如,iphone X截图在远程如果展示为375*812尺寸的图片,可以实现11比例里的操作,当然,可以根据需要进行放大或缩小进行自定义比例转换。

IOS10+网络权限打开问题

因为这套方案是在wda中引入socket通信,使其具备网络传输能力,在实际部署时发现,一定概率wda无法建立socket连接的问题,经过调研发现,是由于我国相关部门出台的新规定指出,应用在未经用户允许的前提下,系统不能授予其使用联网、获取定位的功能。Apple iOS 10 操作系统中加入了关于应用使用数据的授权弹窗提示,用户在iOS 10 系统中第一次打开应用时,会被要求对于是否授予应用联网权限进行选择。而wda是一个无UI的程序,一定概率会无法触发该网络权限的弹窗,导致wda后台进程默认无网络权限。如果没有出现如下弹窗,就会因无网络权限导致无法运行。

解决方法1

使用私有api实现强制弹窗,具体可以参考《私有API-修复iOS 10不弹出"是否允许xxx访问数据"导致app无法联网的bug》这里不再赘述。

解决方法2

分析弹窗触发机制,是app发起网络请求,由系统介入触发弹窗,我们可以反其道而行,让socket通信只作为server端,由mac本地进行转发实现。这里用到了iproxy工具,它是在os x上,苹果的一个叫usbmuxd的服务封装而成,usbmuxd主要用于在USB协议上实现多路TCP连接,将USB通信抽象为TCP通信。苹果的iTunes, XCode,都直接或者间接地用到了这个服务。我们在mac上通过iproxy建立与多个手机的tcp转发即可解决。所以,最终效果是,所有和手机交互的socket通信的请求都是通过mac进行转发的,这样就绕过了wda的网络权限限制。

截屏HierarchyView树结构同步传输效率问题

在远程控制甚至自动化场景,有实时获取屏幕HierarchyView树结构的需求,该方法在wda中快照中遍历获取,一次获取需要2-3s甚至更长时间才能完成,为了提高获取速度,将快照遍历获取逻辑中的,无用属性过滤,只保留常用的namerect属性。这样一次HierarchyView获取在800ms左右,提高了响应速度。

支持多开模拟器

有时候真机确实有限,可以使用FBSimulatorControl工具把1mac上的多个模拟器开启,增加机器数量,模拟器在该方案下同样支持远程控制。

总结

本文提出一种,iOS多机并行远程控制的实践方案,事件流和视频流的性能指标为,事件流毫秒级响应,视频流20-301秒,使得远程控制iOS设备的使用体验逼近测试人员真机测试使用的感受。基于此解决方案可以搭建iOS私有远程控制的集群提高设备利用率或者实现一机操作多机镜像的测试改进工作。

引用:

1、《私有API-修复iOS 10不弹出"是否允许xxx访问数据"导致app无法联网的bug》:

https://www.jianshu.com/p/244c0774b1fb

2WebDriverAgent:

https://github.com/facebook/WebDriverAgent

3ios-minicap:

https://github.com/openstf/ios-minicap

4FBSimulatorControl:

https://github.com/facebook/FBSimulatorControl

5iproxy:

http://iphonedevwiki.net/index.php/SSH_Over_USB

作者介绍

尹飞

百度资深测试工程师,在移动端测试工具改进上有较多实践。目前聚焦移动端兼容性测试效率改进工作上,包括远程控制、UI视觉bug检查等领域。返回搜狐,查看更多

责任编辑:

声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
阅读 ()
投诉
免费获取
今日搜狐热点
今日推荐