了解 uiautomatorviewer 新增的 dump --compressed 功能

新版本的uiautomatorviewer工具中新增了dump --compressed功能,可以选择只获取界面中呈现在你面前的控件,非常精简。那么它是怎么做到的,是更换命令了么?还是在dump的基础上在本地做了一个优化呢?速度怎么样?我带着这些疑惑开始了源码分析之路。

下载源码

google source

配置源码环境

解压缩有项目结构如下:

用你熟悉的方式将源码配置IDE中,我用的是eclipse具体配置过程如下:

虽然它有build.gradle,但是我用这个往eclipse里导入gradle依然没成功,没关系,用暴力的方式。直接创建一个gradle项目,然后将源码copy进去(原谅我的无知),创建的过程看gradle学习(21)-在eclipse中构建java项目 。导入以后肯定有很多错误,这是缺少jar包造成的,添加如下jar包就行了:

所有jar包都可以在你的sdk目录下的tools/lib中找到,其中需要注意一点的是swt.jar包在以x86开始的文件夹中,选择对应平台的jar包就行。

等这些都完成以后,代码中的x号就会消失,项目结构如下:

这个时候在UiAutomatorViewer类中启动main方法,会出现我们熟悉的uiautomatorviewer工具界面:

这个时候你点击Device screentshot按钮会报错:

这是因为uiautomatorviewer项目是根据com.android.uiautomator.bindir属性去找sdk路径的,这就要求你启动的时候需要去添加这个属性。打开DebugBridge类可以看到getAdbLocation()方法中代码:

<span class="n">String</span> <span class="n">toolsDir</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"com.android.uiautomator.bindir"</span><span class="o">);</span> <span class="c1">//$NON-NLS-1$</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">toolsDir</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="n">File</span> <span class="n">sdk</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">toolsDir</span><span class="o">).</span><span class="na">getParentFile</span><span class="o">();</span>

        <span class="c1">// check if adb is present in platform-tools</span>
        <span class="n">File</span> <span class="n">platformTools</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">sdk</span><span class="o">,</span> <span class="s">"platform-tools"</span><span class="o">);</span>
        <span class="n">File</span> <span class="n">adb</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">platformTools</span><span class="o">,</span> <span class="n">SdkConstants</span><span class="o">.</span><span class="na">FN_ADB</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">adb</span><span class="o">.</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">adb</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">();</span>
        <span class="o">}</span>

        <span class="c1">// check if adb is present in the tools directory</span>
        <span class="n">adb</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">toolsDir</span><span class="o">,</span> <span class="n">SdkConstants</span><span class="o">.</span><span class="na">FN_ADB</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">adb</span><span class="o">.</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">adb</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">();</span>
        <span class="o">}</span>

        <span class="c1">// check if we're in the Android source tree where adb is in $ANDROID_HOST_OUT/bin/adb</span>
        <span class="n">String</span> <span class="n">androidOut</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"ANDROID_HOST_OUT"</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">androidOut</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">String</span> <span class="n">adbLocation</span> <span class="o">=</span> <span class="n">androidOut</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"bin"</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span>
                    <span class="n">SdkConstants</span><span class="o">.</span><span class="na">FN_ADB</span><span class="o">;</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">adbLocation</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="n">adbLocation</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>

        <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>

你可以在main方法中加上这个属性,通过System.setProperty(key, value)来设置,key就是上面com.android.uiautomator.bindirvalue值就是你的sdk路径,当然这种方式是不好的,换路径了还得再改,这个很不好的。当然我们不必鸟它,我们采用cts的方式。将返回null值的地方全部用adb代替,代码修改如下:

<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">ADB_COMMAND</span> <span class="o">=</span> <span class="s">"adb"</span><span class="o">;</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="n">String</span> <span class="n">getAdbLocation</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">String</span> <span class="n">toolsDir</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"com.android.uiautomator.bindir"</span><span class="o">);</span> <span class="c1">//$NON-NLS-1$</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">toolsDir</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">ADB_COMMAND</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="o">......</span>

        <span class="k">return</span> <span class="n">ADB_COMMAND</span><span class="o">;</span>
    <span class="o">}</span>

好,这个时候我们再次点击Device screenshot按钮,就可以像往常一样得到设备的界面了和控件信息了:

开始调试

源码搭建完成,就可以进入主题了,开始研究源码了,在ScreenshotAction类中的run方法里打上断点,以Debug As启动应用程序,然后点击Device screentshot with Compressed进入Debug界面。第一行代码自然是我们断点的地方,因为我们主要看dump --compressed这个功能点,其他地方我就不多做介绍了,我加快速度了,直接进入正题,一路debug到了UiAutomatorHelper的静态方法getUiHierarchyFile(IDevice device, File dst, IProgressMonitor monitor, boolean compressed)中,看重要代码(如果你debug不过来,你直接把断点打在下面的代码块就行了):

<span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">getUiHierarchyFile</span><span class="p">(</span><span class="n">IDevice</span> <span class="n">device</span><span class="o">,</span> <span class="n">File</span> <span class="n">dst</span><span class="o">,</span>
            <span class="n">IProgressMonitor</span> <span class="n">monitor</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">compressed</span><span class="o">)</span> <span class="o">{</span>
         <span class="o">......</span>
       <span class="n">monitor</span><span class="o">.</span><span class="na">subTask</span><span class="o">(</span><span class="s">"Taking UI XML snapshot..."</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">compressed</span><span class="o">){</span>
            <span class="n">command</span> <span class="o">=</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"%s %s --compressed %s"</span><span class="o">,</span> <span class="n">UIAUTOMATOR</span><span class="o">,</span>
                <span class="n">UIAUTOMATOR_DUMP_COMMAND</span><span class="o">,</span>
                <span class="n">UIDUMP_DEVICE_PATH</span><span class="o">);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">command</span> <span class="o">=</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"%s %s %s"</span><span class="o">,</span> <span class="n">UIAUTOMATOR</span><span class="o">,</span>
                    <span class="n">UIAUTOMATOR_DUMP_COMMAND</span><span class="o">,</span>
                    <span class="n">UIDUMP_DEVICE_PATH</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="n">CountDownLatch</span> <span class="n">commandCompleteLatch</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CountDownLatch</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
        <span class="k">try</span> <span class="o">{</span>
            <span class="n">CountDownLatch</span> <span class="n">commandCompleteLatch</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CountDownLatch</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
            <span class="n">device</span><span class="o">.</span><span class="na">executeShellCommand</span><span class="o">(</span><span class="n">command</span><span class="o">,</span>
                    <span class="k">new</span> <span class="n">CollectingOutputReceiver</span><span class="o">(</span><span class="n">commandCompleteLatch</span><span class="o">));</span>
            <span class="n">commandCompleteLatch</span><span class="o">.</span><span class="na">await</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="n">TimeUnit</span><span class="o">.</span><span class="na">SECONDS</span><span class="o">);</span>
        <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Exception</span> <span class="n">e1</span><span class="o">)</span> <span class="o">{</span>
            <span class="c1">// ignore exceptions while deleting stale files</span>
        <span class="o">}</span>
        <span class="o">......</span>
    <span class="o">}</span>

执行的命令我们得到

<span class="o">/</span><span class="n">system</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">uiautomator</span> <span class="n">dump</span> <span class="o">--</span><span class="n">compressed</span> <span class="o">/</span><span class="n">data</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">tmp</span><span class="o">/</span><span class="n">uidump</span><span class="o">.</span><span class="na">xml</span>

那第一个问题解决了,就是这是一个新命令dump --compressed(之前没用过,不知道是不是最新的)。我们获得的简洁版的控件信息也不是在本地优化的,是直接在server端传过来就是这样的,这样速度会提高不少。

adb命令实验
C:\Users\hui.qian>adb shell /system/bin/uiautomator dump --compressed /data/loca
l/tmp/uidump.xml
UI hierchary dumped to: /data/local/tmp/uidump.xml

C:\Users\hui.qian>adb pull /data/local/tmp/uidump.xml c:\
394 KB/s (6308 bytes in 0.015s)
C:\Users\hui.qian>adb shell /system/bin/uiautomator dump /data/local/tmp/uidump.
xml
UI hierchary dumped to: /data/local/tmp/uidump.xml

C:\Users\hui.qian>adb pull /data/local/tmp/uidump.xml c:\1.xml
1363 KB/s (21778 bytes in 0.015s)

将上面2个文件进行比较就会发现简洁不少。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值