Xposed 开发之 UiAutomatorViewer 扩展
UI Automator Viewer 是一个 Android SDK 自带的工具,通过它我们可以非常方便的查看和分析 App 的 View Tree,这么好的一个工具,可惜五年没更新了,不过 这个工具是开源的,所以我们可以使用源码进行二次开发。
准备工具
- UiAutomatorViewer源码(Eclipse)
- Eclipse
- Xposed开发环境
配置环境变量
使用 Eclipse 导入项目,然后发现大片的报错,原因是找不到对应的依赖包,问题不大。
删除 build.gradle
里面 dependencies
的项目。
打开 SDK/tools/lib/
目录,会发现有一堆 jar 包,我们需要的依赖包全都可以在这里面找到,但是这么多不可能全都是我们需要的,那么怎么知道我们需要哪些呢?
在这个目录下面找到 uiautomatorviewer-26.0.0-dev.jar
并以 zip 方式打开,找到 META-INF/MANIFEST.MF
这个文件并打开,将 Class-Path
里面的所有 jar 包和 SDK/tools/lib/x86_64/swt.jar
(如果是 32 位系统则找 x86
目录)添加到项目的环境变量里面。
源码分析
我们觉得 Node Detail 里面的属性太少了,我们想往里面添加一些属性怎么搞呢?
从 MANIFEST.MF
文件里面可以得知入口类为 com.android.uiautomator.UiAutomatorViewer
,找到该类的 main 方法:
1 | public static void main(String args[]) { |
在该类的 createContents
方法里面可以找到该 Window 里面的 Actions
省略分析过程,最后找到 com.android.uiautomator.tree.UiHierarchyXmlLoader
这个类,里面的 parseXml
就是解析 xml 的地方,找到这个地方干什么呢?
我们知道 UiAutomatorViewer 的原理是执行 /system/bin/uiautomator dump [--compressed] /data/local/tmp/uidump.xml
这个命令,然后将这个 dump 出来的 xml 文件 pull 到电脑上解析,然后再配上一张截图就可以展示出一个 View Tree。
如果这个文件已经 pull 到电脑上了,我们再想改变里面的数据就比较难了,我们可以在它执行 dump 命令的时候修改里面的属性,然后 pull 到电脑上只负责解析就行了。
仔细查看源码会发现,Node Detail 里面的属性并不是直接定义在 Java 代码里面的,是从 xml 里面循环读出来的,xml 里面有什么就展示什么,那么这些 xml 又是谁写的呢?
顺着 /system/bin/uiautomator
往下找,dump 命令对应的类为 DumpCommand,主要代码:
1 | try { |
继续找 AccessibilityNodeInfoDumper.dumpWindowToFile:
1 | /** |
index
、text
、resource-id
这些不就是 Node Detail 里面的属性么,我们要改变或者往里面新增一个属性怎么办,添加一行 serializer.attribute("", "background-id", "value");
?那么问题来了,怎么添加?这里可是 framework 层的代码,虽然知道这部分代码在 /system/framework/uiautomator.jar
里面,但是代码被转成了 vdex 咋整啊,而且就算解决了这个问题那这个属性的值去哪里找?这一套整下来小白可吃不消,所以我们可以换一种思路。
参考其他的属性,发现基本上都是 node.getXXX
,找到对应的 setXXX
方法,这里使用 Xposed 打印堆栈:
1 | at android.view.accessibility.AccessibilityNodeInfo.setViewIdResourceName(Unknown Source:9) |
多次测试后可以确定:那些 node.getXXX
获取到的值就是在 View.onInitializeAccessibilityNodeInfoInternal
这个方法里面设置的,这样一来就解决了如何获取自定义属性值的问题,我们有了这个 View 的对象实例,什么属性获取不到?
那么最后一个问题,我们怎么把它显示出来呢?
在不修改系统代码的情况下,我们可以这么玩,还记得上面留着一个坑么,UiAutomatorViewer 的源码我们不是还没动过吗,这下就该动手了。
源码修改
在修改源码前,我们需要明确我们要改什么?怎么改?
目的很明确,我们需要添加一些自定义的属性到 Node Detail 里面,怎么添加呢?比如用 json 再包一层:
首先编写 Xposed 模块将我们需要的属性和值添加进去:
1 | XposedHelpers.findAndHookMethod(View.class, "onInitializeAccessibilityNodeInfoInternal", AccessibilityNodeInfo.class, new XC_MethodHook() { |
然后稍稍修改一下 UiAutomatorViewer 解析 xml 的代码:
1 | UiNode tmpNode = new UiNode(); |
修改后:
1 | UiNode tmpNode = new UiNode(); |
手机安装对应的模块,然后再使用这个二次编译的 UiAutomatorViewer 查看布局就行了,效果对比图(点击图片放大):
修改前 | 修改后 |
---|---|
写在后面
- 听说用 idea 也可以编译,这个没试过,懒得折腾了。
- 没有下载链接,代码都在这里了,自己动手丰衣足食。
- 虽然还有一点点不优雅,但是起码实现了想要的功能,在别的优雅解决方案出来之前先凑合用吧。