UiAutomator 二次开发 uiautomatorviewer 优化定位符生成自动化代码实践总结分享

hello · 2018年04月23日 · 最后由 hello 回复于 2020年10月20日 · 2925 次阅读

1,元素定位麻烦

UI 自动化最烦的就是要机械重复的去定位元素,找 Xpath,id 等,虽然安卓 SDK 自带了 uiautomatorviewer 可以查找定位元素,但是里面的 xpath 太长,UI 稍微修改一下,用例就无法通过了。我们需要的是一个相对短的 xpth 去定位元素,以此来保证 UI 变化时,对用例影响最小,基于此自带的 uiautomatorviewer 定位符需要优化。

2,复制粘贴的代码多

找到定位元素的方式后,写的最多的也许就是点点点了。翻译成代码就是【driver.findElement("//android.widget.ImageView[@content-desc='门票']","xpath").click();】,点击元素,输入,获取元素,占用了自动化绝大多数代码量,耗用很多时间,生成重复代码可以帮我们节约很多时间。

为了解决上述两问题,节省复写代码时间,汲取社区很多前辈的经验提供了很好的思路后,二次开发 uiautomatorviewer 优化定位符生成自动化代码。

上个效果图:

  • 定位符优化策略:主要修改源码 UiNode,大家可以参考上面我列举的链接。
    修改 com.android.uiautomator.tree.UiHierarchyXmlLoader,解析遍历 xml,找到相对短的 xpth 去定位元素,uiautomatorviewer 二次开发之自动生成控件定位符说的很详细了。

  • 截图速度优化:主要改造 UIAutomatorview,直接用 ADB 截图。
    主要用到我上一篇文章的方法uiautomatorviewer 获取不到动态页面解决办法调用 UiDevice.dumpWindowHierarchy(),即解决了无法截取动态页面的问题,又提升了截图速度。修改 com.android.uiautomator.UiAutomatorHelper

    private static void getUiHierarchyFile(IDevice device, File dst,
        IProgressMonitor monitor, boolean compressed) {
    if (monitor == null) {
        monitor = new NullProgressMonitor();
    }
    
    monitor.subTask("Deleting old UI XML snapshot ...");
    String strCmdMsg = "rm " + UIDUMP_DEVICE_PATH;
    
    try {
        CountDownLatch commandCompleteLatch = new CountDownLatch(1);
        device.executeShellCommand(strCmdMsg,new CollectingOutputReceiver(commandCompleteLatch));
        commandCompleteLatch.await(5, TimeUnit.SECONDS);
    
        strCmdMsg = "rm " + UISHOT_DEVICE_PATH;
        commandCompleteLatch = new CountDownLatch(1);
        device.executeShellCommand(strCmdMsg,new CollectingOutputReceiver(commandCompleteLatch));
        commandCompleteLatch.await(5, TimeUnit.SECONDS);
    } catch (Exception e1) {
        // ignore exceptions while deleting stale files
    }
    
    monitor.subTask("Taking UI XML snapshot...");
    try {
        CountDownLatch commandCompleteLatch = new CountDownLatch(1);
         strCmdMsg = String.format("%s %s %s", UIAUTOMATOR, "runtest LvmamaXmlKit.jar", "-c com.lvmama.uidump.DumpXml");
        device.executeShellCommand(strCmdMsg,new CollectingOutputReceiver(commandCompleteLatch));
        commandCompleteLatch.await(XML_CAPTURE_TIMEOUT_SEC, TimeUnit.SECONDS);
    
        monitor.subTask("Pull UI XML snapshot from device...");
        device.getSyncService().pullFile(UIDUMP_DEVICE_PATH,dst.getAbsolutePath(), SyncService.getNullProgressMonitor());
    } catch (Exception e) {
    

// throw new RuntimeException(e);
}
}

  • 添加右击菜单:监听选择项,同步点击或者输入手机内页面再截图,生成操作对应代码,类似录制不过是代码录制。
    找到开源包的 com.android.uiautomator;UiAutomatorView 这个 java 文件,主要修改这一块代码 mScreenshotCanvas.addMouseListener(new MouseAdapter() {}

        mScreenshotCanvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseUp(MouseEvent e) {
                if (mModel != null) {
                    mModel.toggleExploreMode();
                    redrawScreenshot();
                }
                 //右击
                if (e.button == 3)
                {
                    Menu menu = new Menu(UiAutomatorView.this.mScreenshotCanvas);
                    UiAutomatorView.this.mScreenshotCanvas.setMenu(menu);
                    Menu clickTypeMenu = new Menu(menu);
                    Menu editTypeMenu = new Menu(menu);
                    Menu longPressMenu = new Menu(menu);
                    Menu findTypeMenu = new Menu(menu);
                    Menu menu4 = new Menu(menu);
                    Menu sendkeyMenu = new Menu(menu);
                    final MenuItem clickItm = new MenuItem(menu, 64);
                    clickItm.setText("Click");
                    clickItm.setMenu(clickTypeMenu); 
    
                    final MenuItem clkRfhItm = new MenuItem(menu, 64);
                    clkRfhItm.setText("Click(ReShot)");
                }
    e.button == 3 就是获得右键事件的判断,给各个菜单绑定监听事件完成相应的处理
                    clickById.addSelectionListener(new SelectionAdapter()
                    {
                      public void widgetSelected(SelectionEvent e)
                      {
                        String src= getSourceByAction(clickById.getText(), clickItm.getText());
                        outpuText(src);
                      }
                    });
    。。。。。
    

    同步输入

实践并总结一下各路大神的无私分享,谢谢各位授之于渔,如有雷同实属参照,改造工具没别的,跟着好的思路分享,就是干!非常感谢,期待大神们分享更多更好的工具思路。
jar 包放到 Git 上了jar 包和具体使用说明
刚完成雏形,还很多要完善的地方,欢迎大家不吝赐教!

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 26 条回复 时间 点赞

源码可以放出来?

恒温 回复

今天太晚了,明天看看吧

bauul 回复

真的么?我好像记得你发一篇苏宁的帖子,找不到你那篇链接了,没加上,参考了你的。你发个链接,我加上🎀 🎀

楼主这个 jar 包能共享出来不

chengen 回复

可以。

仅楼主可见
hello #10 · 2018年04月24日 Author
chengen 回复

放 Git 了,你去下一下吧。

hello #11 · 2018年04月24日 Author
chengen 回复

可以用么?

仅楼主可见
hello #13 · 2018年04月24日 Author
chengen 回复

LvmamaXmlKit.jar 是改进截取 xml 用的,要推到手机里。ADBKeyBoard.apk 是同步输入,解决汉字输入问题的。可以不装,但是不装的话,就不能同步输入了。

hello 回复

请问 l z 的 sdk 是啥版本的呀?我这边在真机上试用获取不到源码哦

hello #15 · 2018年04月28日 Author
water 回复

非常抱歉,我开发时,用的模拟器,真机没试过,我回头修改一下,以支持真机吧。你先用模拟器玩一下下吧😂

hello 回复

哈哈哈~~不错不错!加油撒!

hello #17 · 2018年04月28日 Author
water 回复

你们都是土豪公司全部用真机,我们只能用模拟器,哎,不说了,我去借手机去了~

hello 回复

你好,文档这里文件名的修改与运行文件这里不是很清楚

  • 我电脑 sdk 文件夹只有 uiautomatorviewer.bat ,是用 \autotest_helper\下面的 uiautomatorviewer.jar 覆盖? 执行 uiautomatorviewer.jar 后连接不上,执行自己的 uiautomatorviewer.bat 可以连接上,不过就没有二次开发的功能。
iiFeng 回复

噢我看到了。文件路径这里没看清楚,uiautomatorviewer.jar 在文件夹 \tools\lib 里。运行成功了

不过,页面移动时会闪屏,底部驴妈妈的背景与我的页面混合显示,请问什么原因

hello #20 · 2018年06月08日 Author
iiFeng 回复

闪屏问题,是设置背景图片的问题,我后期优化一下,非常抱歉啊

hello 回复

好~ 提了 issue

请问一下我部署好之后,打开 uiautomatorviewer 还是原来的旧页面呢,没有选择 java 和 python 的地方

hello #24 · 2018年08月06日 Author
刘光磊 回复

那说明 bat 没有启动到新的 jar 包啊。你原来的包备份成.zip

截图的时候报错 Error while parsing UI hierarchy XML file: null[Ljava.lang.StackTraceElement;@6d44ee69
文件加载异常:C:\Users\xx\AppData\Local\Temp\uiautomatorviewer_2513040776586100887\dump_254253929936287447.uix
怎么解决啊

hello #28 · 2020年10月20日 Author
aiyumo 回复

SDK 版本多少?

3楼 已删除

这个还可以兼容 ios 录制呢,好好玩 😀

这个跟用 appium 录制很像啊

hello #26 · 2018年08月31日 Author
king 回复

录制我没试过,这个也是刚刚研究。Appium 还可以录制么,我研究学习一下

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册