背景
在Android开发中,有这样的情形:
- 手机连接在本机,但是因为在一边调试,不方便同时拿着手机看结果(手机屏幕和PC屏幕来回切换较麻烦),期望手机屏幕与调试程序的屏幕同时在PC的屏幕一并展示,这样更加便捷;
- 调试(或测试)的手机并非连接在本机上,此时需要在测试的时候在本机上同步查看远端手机的屏幕(调试时实时的展示)。
在上述情况下,就需要将调试的手机屏幕通过一定技术手段在PC屏幕上实时展示。通过查询资料和实践,目前总结出两种方法可以达到目标。
原生adb方式
我们知道,Android调试都是通过adb来实现。adb原理看似简单,其实涉及到的知识和原理很多也比较复杂,要想完全弄清楚adb的原理和运行机制,除了查阅官方资料、网上的相关资料(这里提供两份参考资料,请下载adb原理.pdf、Android远程控制技术.pdf,不过个人认为这两份资料并未将adb原理讲透将明白,也缺乏实际的场景抓包说明),实际动手(抓包、测试)都不可少,本文暂不对adb原理进行展开,后续会单独写一篇adb的原理介绍。
这里以windows系统为例,开发人员常使用adb.exe,在命令行下执行各种adb命令,比如截图adb shell screencap /sdcard/your_path.png
。那么既然通过adb命令可以截图,我们是否可以想到,如果不停地执行截图,然后将N张截图以类似播放电影的方式连贯起来,那不就相当于实时查看手机屏幕了吗。
看起来这个方式应该可行,但是存在两个问题:
adb shell screencap
命令截图,耗时还是比较多,一般在1-2s之间,而且对手机资源消耗也比较多,不停截图的话,CPU和其他资源占用就更多了,可能影响正在调试的APP的测试指标;- 还需要单独对adb.exe的命令行使用进行代码封装,原理虽简单,但是做这些重复性的活很让人厌烦。
对于问题1,我们可以通过minicap的方式来解决;对于问题2,其实Android SDK包里面已经有相关工具库可供使用,那就是ddmlib,位于%ANDROID_HOME%\tools\lib\
目录下(其中%ANDROID_HOME%
表示Android SDK的安装目录),名字一般叫ddmlib-x.y.z-xx.jar
(x.y.z-xx表示版本号,建议更新Android SDK至最新版)。关于ddmlib,网上资料相对较少,可以查看jar包的源码进行详细的研究,也可以参考网上已有的部分资料(比如github上一个ddmlib封装库https://github.com/cosysoft/device)。ddmlib相当于提供了一个adb client,提供了调用的接口,可以实现连接设备,发送和执行adb命令,获取结果等等,也就是说,大家平时通过adb.exe能干的事情,ddmlib都可以做到,提供了很好的封装和调用接口,其实Android的DDMS工具和其他类似工具等底层都是通过调用ddmlib实现调试和操作的。
但是,我们这里仍然不直接使用ddmlib,为什么呢,答案就是“站在巨人的肩膀上前进”。其实Github上已有一个较好的实现android-screen-monitor,该实现基于ddmlib,另外还使用到chimpchat(与ddmlib库一样,位于位于%ANDROID_HOME%\tools\lib\
目录下,名字一般叫chimpchat-x.y.z-xx.jar
)和google的guava库。
从Github将android-screen-monitor工程clone下来之后,通过Eclipse导入工程,效果如下:
对工程源码进行定制或二次开发之后,可以将工程导出为一个可执行jar包。
minicap和minitouch
该方式基于Github上一个比较有名的云测手机测试项目STF项目的两个子项目minicap、minitouch。其中minicap实现屏幕实时展示,而minitouch实现模拟点击和滑动,从而可以在本机上直接操作手机,就如同直接在手机上点击和滑动一样。
minicap的原理大致为(可详细查看minicap Github的readme):
- 在手机端通过minicap.so(Android NDK开发,其基于Android底层开发,从设备底层获取屏幕的数据)
- minicap可执行文件,在手机端开启一个socket server,接收来自PC客户端的连接,将屏幕帧流不断发送至PC端的socket client
- PC端通过adb forward命令实现socket连接转发,因为PC连接Android手机一切都通过adb server。PC的socket client通过adb forward转发连接至minicap开启的socket server,读取其发送的帧流,然后在PC端处理之后即可通过GUI程序或者web页面展示。
关于minicap实现手机屏幕实时展示,官方Github仓库的sample中提供了NodeJS的示例,而python和java的示例在网上已有很多人实现过(本文后续会提供一份python版本的实现),可以参阅: