zoukankan      html  css  js  c++  java
  • Airtest源码分析--Android屏幕截图方式

    上期回顾:Airtest之iOS API汇总


    以下基于airtest1.2.0

    airtest中安卓的屏幕截图代码都在
    /airtest/core/android/cap_methods/

    该目录结构为
    .
    ├── base_cap.py
    ├── adbcap.py
    ├── javacap.py
    ├── minicap.py
    └── screen_proxy.py

    base_cap.py

    其中的BaseCap类是所有屏幕截图方法的基类,定义了一些基本的方法,其他具体截图方法类使用或重写这些方法。

    minicap.py

    minicap是stf框架内置的一个截图工具,通过建立websocket连接,支持实时传输手机屏幕stream到PC端。
    https://github.com/openstf/minicap

    Minicap类基于stf的minicap。通过adb forward设置airtest和手机端的端口映射关系,建立一个socket持续获取minicap stream,应该就是airtestIDE中的投屏基础。

        def get_stream(self, lazy=True):
            """
            Get stream, it uses `adb forward`and socket communication. Use minicap ``lazy``mode (provided by gzmaruijie)
            for long connections - returns one latest frame from the server

            Args:
                lazy: True or Fals
            """
            gen = self._get_stream(lazy)

            # if quirk error, restart server and client once
            stopped = next(gen)

            if stopped:
                try:
                    next(gen)
                except StopIteration:
                    pass
                gen = self._get_stream(lazy)
                next(gen)

            return gen

    通过adb minicap -s命令获取一帧截图,以实现airtestIDE中的截图及对比的基础。

        def get_frame(self, projection=None):
            """
            Get the single frame from minicap -s, this method slower than `get_frames`
                1. shell cmd
                1. remove log info
                1.   ->   ...

            Args:
                projection: screenshot projection, default is None which means using self.projection

            Returns:
                jpg data

            """
            params, display_info = self._get_params(projection)
            if self.display_id:
                raw_data = self.adb.raw_shell(
                    self.CMD + " -d " + str(self.display_id) + " -n 'airtest_minicap' -P %dx%d@%dx%d/%d -s" % params,
                    ensure_unicode=False,
                )
            else:
                raw_data = self.adb.raw_shell(
                    self.CMD + " -n 'airtest_minicap' -P %dx%d@%dx%d/%d -s" % params,
                    ensure_unicode=False,
                )
            jpg_data = raw_data.split(b"for JPG encoder" + self.adb.line_breaker)[-1]
            jpg_data = jpg_data.replace(self.adb.line_breaker, b" ")
            return jpg_data

     

    adbcap.py

    AdbCap类就是通过adb shell screencap -p来获取屏幕截图

    class AdbCap(BaseCap):
        def get_frame_from_stream(self):
            warnings.warn("Currently using ADB screenshots, the efficiency may be very low.")
            return self.adb.snapshot()

        def snapshot(self, ensure_orientation=True):
            screen = super(AdbCap, self).snapshot()
            if ensure_orientation and self.adb.sdk_version <= SDK_VERISON_ANDROID7:
                screen = aircv.rotate(screen, self.adb.display_info["orientation"] * 90, clockwise=False)
            return screen

    看一下其调用的adb.snapshot()方法

    def snapshot(self):
        """
        Take the screenshot of the device display

        Returns:
            command output (stdout)

        """
        if self.display_id:
            raw = self.cmd('shell screencap -d {0} -p'.format(self.display_id), ensure_unicode=False)
        else:
            raw = self.cmd('shell screencap -p', ensure_unicode=False)
        return raw.replace(self.line_breaker, b" ")

    javacap.py

    Javacap类基于yosemite作为service,建立socket连接和airtest通讯,提供截图。性能比minicap差,但兼容性高,有些机型不支持minicap。

    screen_proxy.py

    ScreenProxy类,屏幕代理,airtest1.2.0引入。在以前遇到特殊机型,是要提供特殊的连接参数的,如cap_method="JAVACAP",或在airtestIDE连接前选中JAVACAP。

    从airtest1.2.0、airtestIDE1.2.10开始,就不需要再指定连接参数了,airtest会自己去进行适配,按性能初始化顺序为自定义方法 > MINICAP > JAVACAP > ADBCAP,如果调用到了ADBCAP,将会打印一个warning,告诉用户此时截图效率很低。

    这样,以后无需再关注底层到底用的是谁,需要截图时直接通过screen_proxy即可,例如:

    dev = Android()
    screen_proxy = ScreenProxy.auto_setup(dev.adb, rotation_watcher=dev.rotation_watcher)
    screen_proxy.get_frame_from_stream()
    screen_proxy.teardown_stream()

    如果希望实现自定义的新截图方法:在airtest.core.android.cap_methods.base_cap中,实现了所有截图方法的基类BaseCap,可以通过继承它,并实现get_frame_from_stream这个接口,就能新增一个自定义的截图方法,将它注册到ScreenProxy中就可以使用了。

    from airtest.core.android.cap_methods.base_cap import BaseCap
    class TestCap(BaseCap):
        def get_frame_from_stream(self):
            return b"frame"

    ScreenProxy.register_method("TESTCPY", TestCap)
    # 默认优先初始化为自定义的TestCap
    cap = ScreenProxy.auto_setup(dev.adb)

    总结

    划重点,MINICAP性能最好,JAVACAP性能次之但兼容性好,ADBCAP性能最差。

    ---------------------------------------------------------------------------------

    关注微信公众号即可在手机上查阅,并可接收更多测试分享~

  • 相关阅读:
    批量导入
    循环语句
    判断循环常见
    常见C运算符
    oc将字符串中单词按照出现次数(次数都不一样)降序排序,排序之后单词只出现一次,源字符串中单词用下划线连接,生成字符串也用下滑线连接
    把字符串中的字母大小写反转OC
    查找子串出现次数OC
    现有一个数组NSMutableArray, 数组有若干个NSString的元素,进行选择法排序
    终端的一些命令
    编程语言名字来历
  • 原文地址:https://www.cnblogs.com/songzhenhua/p/15315249.html
Copyright © 2011-2022 走看看