几乎每个云测平台或手机厂商都有云真机业务,解决了小团队真机设备覆盖不足、资产管理困难的问题,让开发者可以像本地设备一样在线操控和调试设备。云真机平台一般附带一些辅助操作平台,可以通过拖拽的方式安装APP,同步黏贴板,查看log,截屏跑自动化,等等这些都可以在浏览器内完成,确实给研发测试都带来了不少便捷。
云真机通过一个设备管理系统,将这些真机对外租用,相比于传统的实体机租用,在线租用免去了实体机快递和硬件损坏风险的问题,随租随用,资费透明。
但他们都有一个共同点,贵,超级贵,按秒计费。
主流的云真机平台有腾讯WeTest远程调试、TestIn远程真机、百度测试云真机等,下面是百度云真机官网的介绍。
在讲云真机之前,需要先说说什么是ADB。
全名:Android Debug Bridge
官方解释:
Android 调试桥 (adb) 是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。
ADB可分为三个部分:
ADB的后台程序相当于一个跑在手机上的服务器,通过约定的协议以TCP的方式和PC的客户端交互,执行命令。比如 adb install命令,实际上是往手机上传了一个apk文件,然后告诉手机的安装程序安装这个apk;比如断点调试代码,实际上是IDE和手机之间通过adb互传代码执行信息,代码行号之类的。
研发可以通过开启一个SocketServer来欺骗adb,执行adb connect命令就会显示连接了一个设备,可以看到每条adb命令发出的是什么样的报文,当然孤独的adb是得不到任何回应的,它连的是假的设备。
adb的权限极大,可以在偷偷的执行命令而用户看不到,就像电脑上安装了360杀毒软件,连上手机后,手机上会默默的多出一个360安全助手APP。。。
这个后台程序默认是不开启的,当你打开和关闭手机开发者设置里面的调试模式后,其实就是在开关这个后台程序。
所以不建议普通用户的手机打开这个功能,哪怕360给你说出一万个打开调试模式的好处,也不要开。
这些云测平台没有骗你,真的在云端跑了大量的真机,不是虚拟机不是模拟器。所以贵也是有道理的,当你租用这个手机的时候,就是独占了一台价值不菲的设备,消耗着不小的带宽。
云真机本质上就是远程控制手机,并且通过API的方式间接调用adb命令和手机交互。
云测平台的服务器通过一些高端的USB HUB连接了很多真机,再通过一个设备管理系统,将手机屏幕类似直播的方式显示到用户的浏览器上,再接收浏览器的上的手势操作回传给服务器。
云真机原理
上面提到这些云测平台的云真机服务,基本都是在一个叫STF的开源软件基础上定制开发而来的。
STF 全名Smartphone Test Farm,是一个安卓设备管理在线平台(也在扩展ios支持),刚开始被设计用来将将公司内部众多的安卓设备资产统一管理,并可以直接在个人电脑上在线使用手机,后来这些云测平台改改UI,变成了一个对外租用服务。
STF架构的官方说明可以看看GitHub上的DEPLOYMENT.md
这个有点不好理解,这里画个简版的架构图:
这里面几个关键角色介绍一下:
运行效果
上面所有的服务都可以是一台独立的电脑,也可以部分或全部在同一台电脑上。部署方式分为单机和集群两种。
单机就是所有的服务都部署在同一台电脑上,用于自己使用。
stf的安装成功是比较困难的,命令其实很简单,主要是一些依赖库可能需要,因此建议下面的所有安装命令都要在状态下运行。安装失败建议卸载已安装的模块,全部重新安装。
安装:
首先,安装依赖项,Mac为例:
brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config
然后再安装stf:
npm install -g stf
运行:
先启动rethinkdb:
只需要在命令行中通过rethinkdb命令启动;
再启动服务:
对于单机版,有一个快捷的命令以默认配置一键启动所有服务:
stf local --public-ip
—public-ip 是你的内网ip,这样局域网内的其他同学也可以远程你电脑上的手机,不加这个参数就只能本机访问。
使用:
默认的web服务端口是7100,因此在浏览器输入http://localhost:7100即可使用。
接入手机,设备列表上会自动出现手机并且标记为在线状态,点击该设备就可以进入远程控制状态;拔下手机就会自动标灰,无法远程。
集群就是将部分模块独立部署,以缓解节点压力,上面的每一个服务都是可以独立部署的,并且像设备提供方、web服务器、代理服务器都是可以集群的。
一种简单的集群模式可以是:
将除设备提供服务外的所有服务部署在一个公网服务器上,而在每个人的电脑上部署一个设备提供服务。
这样,每个人电脑上的部署就相对简单,而且每个人都可以将自己电脑上的设备连接到服务器上,统一管理。
stf provider --name "%H/%i" --connect-sub tcp://devside.stf.example.org:7250 --connect-push tcp://devside.stf.example.org:7270 --storage-url https://stf.example.org/ --public-ip ${COREOS_PRIVATE_IPV4} --min-port=15000 --max-port=25000 --heartbeat-interval 10000 --screen-ws-url-pattern "wss://stf.example.org/d/%i/<%= serial %>/<%= publicPort %>/"
docker部署的成功率最高,但是在Mac下docker和宿主机无法共享USB设备,所以无法提供设备,其他其他的可以尝试。也在上面的官方部署里面有提到。
这里可以参考美团点评云真机平台实践(https://tech.meituan.com/2018/07/19/cloud-phone.html),可以扩展的方向包括:简单的页面改造、账户集成KMS、集成Jenkins自动化测试(使用API上传apk直接安装指定到测试机)、跨局域网部署(比如把Websocket换成WebRTC,使用SocketServer模拟设备转发)等等。反编译了阿里云真机的客户端程序源码,其真是通过本地开启了一个SocketServer中转云端真机的adb数据流,而我们本地Android Studio链接的设备其实是这个SocketServer,阿里云通过这个SocketServer实现了云真机的一些权限校验工作。
背景
目前市場上,雲真機平台實時投屏主要有兩種工具:STF的minicap和GenyMotion的scrcpy;STF的minicap工具是採用截圖的方式實現實時投屏,但是minicap工具根據google發布的Android版本對應不同的工具文件,當新的Android發布時,minicap的適配版本還未及時發布可能會影響用戶體驗。Scrcpy通過獲取視頻數據實現實時投屏,但是只能支持Android 5.0以上。因此,目前這兩種投屏方式都有各自的優缺點。
我們平台採用兩種方式結合的方式,用來儘快適配google發布的android版本。最近,在新手機上線過程中,發現有些品牌(如vivo,oppo)的手機無法使用Scrcpy工具進行實時投屏,通過分析發現其H264的碼流是High檔次,而前端H264數據播放插件只支持baseline檔次的碼流。
這個問題,有兩種解決方式:一個是前端播放插件對應不同的碼流進行切換,還有一種是修改原始碼流,此處我們選擇了後者。
方案
以小米9手機爲例 (Android 9.0),雖然STF的minicap工具已經對Android 9.0進行了適配,但是前端播放插件不支持H264 baseline以外的碼流。H264格式數據的碼流通過profile_idc欄位標識,小米9獲取到的H264格式數據如圖所示:
其中profile_idc標識碼流有兩個檔次,100即High檔次碼流,66表示baseline檔次碼流。碼流的取值是由手機硬體決定的。通過scrcpy源碼(https://github.com/Genymobile/scrcpy)發現 ScreenEncoder 文件中有個 createForma t私有方法可以指定視頻流數據的格式,因此我們通過修改該方法的代碼,人爲的將視頻流數據格式化爲baseline,具體如圖所示:
修改完源碼之後實時投屏實現主要包括以下幾個步驟:
1. 將scrcpy源碼重新編譯成jar包,將jar包push到手機中。
2.在手機中執行命令
CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / --nice-name=scrcpy_servercom.genymobile.scrcpy.Server 0 8000000 true weight:height:0:0 false
其中weight和height是手機的寬度和高度。(需要注意的是每次執行命令後,之前push到手機中的jar包會被清除,所以每次啓動命令都需要pushjar包)
3.執行`adb forward`命令forward埠和手機進行socket通信連接。以獲取視頻流數據。
4.將獲取的視頻流數據解析成單條H264數據再轉發給web端,web端通過插件播放視頻流,最終實現實時投屏的效果。
修改後scrcpy.jar獲取得到的視頻流解析數據如圖所示,通過H264分析工具可以看到H264格式的數據profile_idc變成了66,碼流變成baseline格式。達到我們想要的效果:
最終效果
前端播放使用Broadway插件