用 UIAutomatorview 获取控件,我觉得是好慢,我用的模拟器 (BlueStacks),手机没统计过不过也快步了多少,不管什么控件都差不多 9 秒,这效率是无法忍受的,即使你是压缩,其实慢的不是获取 XML 文件,而是慢在截图,空余时间每次一小步


查看 UIAutomatorview 截图实现代码


rawImage = device.getScreenshot();  //自带的截图方式,那么看看里面是什么

static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device) throws TimeoutException, AdbCommandRejectedException, IOException {
        RawImage imageParams = new RawImage();
        byte[] request = formAdbRequest("framebuffer:");
        byte[] nudge = new byte[]{(byte)0};
        SocketChannel adbChan = null;

        Object var11;
        try {
            adbChan = SocketChannel.open(adbSockAddr);
            adbChan.configureBlocking(false);
            setDevice(adbChan, device);
            write(adbChan, request);
            AdbHelper.AdbResponse resp = readAdbResponse(adbChan, false);
            if(!resp.okay) {
                throw new AdbCommandRejectedException(resp.message);
            }

            byte[] reply = new byte[4];
            read(adbChan, reply);
            ByteBuffer buf = ByteBuffer.wrap(reply);
            buf.order(ByteOrder.LITTLE_ENDIAN);
            int version = buf.getInt();
            int headerSize = RawImage.getHeaderSize(version);
            reply = new byte[headerSize * 4];
            read(adbChan, reply);
            buf = ByteBuffer.wrap(reply);
            buf.order(ByteOrder.LITTLE_ENDIAN);
            if(imageParams.readHeader(version, buf)) {
                Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size=" + imageParams.size + ", width=" + imageParams.width + ", height=" + imageParams.height);
                write(adbChan, nudge);
                reply = new byte[imageParams.size];
                read(adbChan, reply);
                imageParams.data = reply;
                return imageParams;
            }

            Log.e("Screenshot", "Unsupported protocol: " + version);
            var11 = null;
        } finally {
            if(adbChan != null) {
                adbChan.close();
            }

        }

        return (RawImage)var11;
    }

里面是通过 scoket 交互了好几次,获取 data 的时候特别慢


改造,直接用 ADB 截图


String command = "rm /sdcard/screenshot.png";
        command = "adb shell rm /sdcard/screenshot.png";
run(command);

command = "adb shell /system/bin/screencap -p /sdcard/screenshot.png";
        run(command);

command = "adb pull /sdcard/screenshot.png " + System.getProperty("user.dir");
        run(command);
        Picture.rotate(System.getProperty("user.dir") + File.separator + "screenshot.png"); //我用的模拟可能有问题,截图之后不是竖屏,那么自己旋转下,方式网上有

public static UiAutomatorResult takeSnapshot 方法修改,直接在入口起一个新的线程,不管 XML 获取没获取先把图截了


//入口不用管获取没获取到XML文件,直接起线程获取截图
ScreenShotUtil screenShotUtil = new ScreenShotUtil();
        Thread threadScreenShotUtil = new Thread(screenShotUtil);
        threadScreenShotUtil.start();

//文件结尾,自带的那些代码全部删掉,sPath是你保存图片的地方
ImageData imageData = new ImageData(sPath);
        Image screenshot = new Image(Display.getDefault(), imageData);
        return new UiAutomatorResult(xmlDumpFile, model, screenshot);

改完成之后那个酸爽,提升了 7-9 倍


在联想一下我之前写的文章,https://testerhome.com/topics/4545
既然效率这么高了,那么我在操作 APK 或者系统事件的时候,可以反调生成控件的按钮,也就是实现了伪录制的效果


输入文本信息,这里只有在 appium 脚本执行成功后才会刷新


自动刷新控件中


刷新之后的控件,这个有一个问题,就是目前的方式获取控件太快了,导致 app 可能跳转慢,截的图是未加载完成的,待改进


↙↙↙阅读原文可查看相关链接,并与作者交流