我最早接触到UI Automator Viewer这个工具,其实是踩了Layout Inspector的坑以后才认真去研究的。当时某公司让我们做一款 App 的 UI 自动化测试,界面元素定位始终搞不定,一直用的 Android Studio 里的 Layout Inspector 要么连不上,要么对第三方应用显示不出来。后来换用 UI Automator Viewer 之后,问题才真正解决:它不依赖应用是否可调试,只要能跑起来,就能抓取界面层级。
这篇博文就把我在实际工作中用 UI Automator Viewer 分析微信、支付宝这些第三方 App 布局的经验完整整理一遍,包括环境准备、完整实操、属性解析、高频报错,以及如何把抓取结果接到自动化测试脚本里。适合正在做 UI 自动化测试的新人、需要做竞品界面分析的开发者,以及想了解 Android 无障碍视图机制的读者。
1. 为什么放着 Layout Inspector 不用,偏要去折腾 UI Automator Viewer
先聊清楚一个问题:Android Studio 自带的 Layout Inspector 明明界面更漂亮、层级更直观,为什么还要用 UI Automator Viewer 这个看起来老掉牙的工具。
1.1 Layout Inspector 的先天局限
Layout Inspector 是 Android Studio 开发环境下用的调试工具,它底层依赖的是应用进程内部的视图树信息。也就是说,它只能查看 Debuggable 的应用。你自己开发的项目,或者通过 Debug 模式启动的应用,可以正常查看。但换成市场里下载的微信、支付宝这种 release 包,Layout Inspector 几乎什么都拿不到。
我实测下来,Layout Inspector 对非 Debuggable 应用的表现通常有两种:
- 连接不上目标进程,提示类似 “The layout inspector could not be attached”;
- 能打开一个空白的界面,看不到任何 View 节点。
换句话说,你没法在 Android Studio 里用 Layout Inspector 去分析第三方 App 的界面。做竞品调研、无障碍适配、UI 自动化脚本开发的时候,这条路直接堵死了。
1.2 UI Automator Viewer 的替代优势
UI Automator Viewer 是 Android SDK 里自带的工具,它的底层机制和 Layout Inspector 完全不同。它通过 Android 系统的 accessibility 服务能力去获取当前窗口的界面层级,相当于系统从无障碍通道打包了一份界面信息给你。
它的几个突出优势:
- 不要求应用可调试,普通安装的 release 包也能抓取界面层级;
- 不需要额外装什么插件,SDK 里拿出来就能用;
- 能直接看到 View 的
resource-id、text、content-desc、bounds等核心属性,这些正是写 UI 自动化测试脚本时最需要的定位信息; - 轻量,比 Layout Inspector 省内存,列举上百个节点的界面时依然流畅。
也因为走的是无障碍通道,很多手机厂商在系统优化时会限制部分后台应用的 accessibility 数据,个别情况下需要开启特定的“USB调试(安全设置)”选项才能读取完整 UI,这点在后面常见问题里我会细说。
2. 开工前的环境准备,这些坑提前避掉
UI Automator Viewer 的使用流程本身不复杂,但环境不出问题,操作就能减少一大半干扰。
2.1 装好 Android SDK 和 platform-tools
新版本的 Android Studio 里,很多老工具默认不再打包到 IDE 目录里了,所以你有可能遇到一个尴尬情况:命令行敲uiautomatorviewer提示找不到命令。我的解决方法是单独下载 Android SDK 命令行工具,或者直接找旧版 SDK 里的 tools 目录。
如果你用的是完整的 SDK 目录,uiautomatorviewer的路径如下:
- Windows:
sdk\tools\bin\uiautomatorviewer.bat - macOS/Linux:
sdk/tools/bin/uiautomatorviewer
正常情况下,先配置好ANDROID_HOME环境变量,然后在命令行里直接执行启动脚本就行。如果启动时报 Java 相关错误,说明 JDK 环境没配置好,或者 JDK 版本和工具不兼容。我通常用的 JDK 8 或 JDK 11 都能正常跑。
2.2 连接设备的关键检查项
工具本身是连接 ADB 设备来截图的,所以设备连不上,后面一切都白搭。
在命令行里先用adb devices确认设备状态。正常会看到类似:
List of devices attached <序列号> device如果显示unauthorized,那就去真机上弹窗点“允许 USB 调试”。如果压根没显示设备,检查数据线是否支持数据传输(市面上很多线只能充电),或者换一个 USB 口。
多台设备连接时,需要在工具里选择设备。或者在启动前用adb -s 设备序列号操作对应设备。真机调试时还有个容易忽略的细节:部分国产 ROM 出于隐私保护,默认会在连接电脑调试时屏蔽 UI 无障碍信息抓取,导致 uiautomatorviewer 截出来是黑屏或者只剩状态栏。这种情况下,需要到开发者选项里开启类似“USB调试(安全设置)”的开关,不同品牌的名称可能不太一样,核心意思是允许通过 USB 模拟点击和读取 UI 信息。
模拟器用户也要注意,uiautomatorviewer 对模拟器同样是走 ADB,所以只要adb devices能识别,基本能用。但一些虚拟机里跑的游戏或者特殊图形引擎应用,界面可能不是传统 View 结构,抓出来的数据量也很小,这点后面会单独讲。
3. 手把手实操:UI Automator Viewer 完整使用流程
环境准备好以后,后面这一步一步的流程就是日常用的核心了。
3.1 启动工具和截取界面
启动 uiautomatorviewer 后,界面是一个很复古的 Java Swing 窗口,左边是手机截图,右边是节点树,上方一排小图标。
我习惯的操作流程是:
- 先把 App 切到想分析的页面;
- 打开 uiautomatorviewer;
- 点击左上角那个类似“设备截图”的图标(一个手机加绿色刷新箭头的图标);
- 等待 1~3 秒,工具会自动通过 ADB 触发
uiautomator dump并抓取当前窗口层级; - 左侧出现截图,右侧出现完整的 View 节点树。
这里要提醒一个高频菜鸟错误:直接打开工具就截图,但手机屏幕是熄灭的,或者停留在锁屏界面。这种情况下抓到的层级就是锁屏页,不是你想分析的页面。正确做法是先让手机保持亮屏、停留在目标页面,再点截图按钮。
3.2 从节点树里读懂界面结构
抓取成功后,右侧的节点树会显示整个窗口的 View 层级。默认是一棵从上到下的树,根节点通常是android.widget.FrameLayout,下面一层一层展开,包含各种LinearLayout、RelativeLayout、RecyclerView、TextView、ImageView之类的节点。
点击树里的任意节点,左侧截图里对应的区域会高亮显示。这个功能非常实用,尤其是你想知道界面上某个按钮、某个输入框到底对应哪个 View 节点时,挨个点击就能对应起来。
如果节点树很深、很多,可以直接在左侧截图里点击元素,然后右侧会自动选中对应的树节点,操作效率更高。
3.3 关键属性的含义与取值技巧
选中一个节点后,界面下方面板会显示它的属性列表。日常用到最多的是这几个:
| 属性 | 含义 | 定位价值 |
|---|---|---|
text | 控件显示的文本内容 | 用文本定位元素最直观 |
resource-id | 布局里定义的资源 ID | 自动化测试中最稳定的定位方式 |
class | View 的具体类型 | 判断控件类型很有用 |
package | 所属应用包名 | 确认元素归属 |
content-desc | 无障碍内容描述 | 对于没有文本的图标按钮很关键 |
bounds | 控件在屏幕上的坐标范围 | 手写坐标点击、区域校验必备 |
举例来说,界面上一个“登录”按钮,它的属性常常长这样:
text: "登录" resource-id: "com.example.app:id/btn_login" class: "android.widget.Button" bounds: [108,1836][972,1980]bounds的格式是[左,上][右,下],中心点坐标 X = (108+972) / 2 = 540,Y = (1836+1980) / 2 = 1908。这个中心点可以直接用于 Appium 的坐标点击或者无障碍服务的注入点击。
4. 实战场景:分析微信好友列表和支付宝首页 Tab
理论知识讲多了没意思,拿真实界面走一遍流程才有感觉。
4.1 分析微信某界面布局实录
以微信通讯录界面为例。先用手机打开到“通讯录”页,点 uiautomatorviewer 里的截图按钮。抓取完成后,右侧节点树会先出现一个整体的扁平层级,然后在中间部分看到 RecyclerView 相关的节点。
再看节点属性。你会发现通讯录界面上每个好友的条目通常长这样:
- 外层是一个
android.widget.RelativeLayout,bounds 覆盖整个列表项的高度; - 里面有一个
android.widget.TextView,text 就是好友昵称; - 旁边可能有一个
android.widget.ImageView,content-desc 可能为空,因为它只是头像图片。
这里有个非常容易被忽略的坑:微信这种大厂应用,很多控件的resource-id是空的。resource-id只显示package名加一个斜杠,或者直接空着。所以你不能指望靠resource-id去精确定位微信里的元素,反而是text属性比较可靠。要拿“朋友圈”入口这种非文本区域时,就得靠content-desc或者镜像坐标了。
微信页面里动态加载的会话列表尤其有意思。你切换聊天记录、翻动列表时,底层的 View 复用非常明显,dump 出来的树结构和界面上看到的数量不完全对应。这是 RecyclerView 的复用机制导致的,不是工具抓取出了 bug。分析这种场景时,要把注意力放在“可复用的 item 模板”上,而不是单个具体数据条目。
4.2 分析支付宝首页 Tab 实录
再看支付宝首页。首页结构相对稳定,底部那几个 Tab 是典型的定位目标。
抓取首页后,点选底部 Tab 里任意一项,属性面板里一般能看到:
text: "首页" class: "android.widget.TextView" bounds: [0, 2130][270, 2280]如果你是在写自动化用例,想点击“理财”Tab,直接用 text 来匹配就足够了。但需要注意,如果页面同时出现两个 text 完全相同的控件,直接按 text 定位会命中多个元素。这时候要么用bounds过滤,要么先定位父节点再往下找子节点。
支付宝首页还有一个很典型的情况:顶部搜索框并不是原生 EditText,很多版本里是个假搜索框(可能是 TextView 加背景样式模拟的)。你抓取下来发现class是android.widget.TextView,text却是空或者一串“搜索”提示文案。这种情况千万别硬按 EditText 去定位,按实际 class 来反而轻松。
再说一个特殊细节:支付宝很多常用的页面是原生 View 和 WebView 混排的,比如活动运营页。uiautomatorviewer 在 dump 时会把 WebView 整体当作一个android.webkit.WebView节点,内部的网页 DOM 结构它是看不到的。想分析 WebView 内部的元素,需要另开chrome inspect或者用它自带的 chromedriver 调试机制,这一步不在本文范围,但你知道这个边界能少走很多弯路。
5. 高频报错与排查方法(踩坑合集)
用这个工具快两年了,遇到过不少报错,挑几个典型的说说。
5.1 连不上设备、截图一直转圈
最常见的错误是点击截图按钮后,左侧一直显示加载状态,等多久都不出图。这种问题八成不在工具本身,而在 ADB 连接状态。
我的排查路径是:
- 看命令行里
adb devices是否能识别设备; - 如果识别了但状态是
unauthorized,重插数据线,在手机上重新允许 USB 调试; - 如果状态是
device但依然白屏,执行adb kill-server和adb start-server,然后重启 uiautomatorviewer 再试。
还有一种场景:电脑上装了多个平台工具版本,某个模拟器自带的 ADB 版本和 SDK 里的不一致,也会导致连接不上。统一用同一个platform-tools目录下的adb能解决大部分问题。
5.2 节点树乱码、卡顿和界面显示不全
有时候抓取成功,但节点树里的中文文本显示成乱码。这是 Java 工具的编码问题,Windows 环境下尤其容易出现。可以在系统环境变量里加JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8,然后重启工具,基本能解决。
界面节点特别多的时候,右侧树会卡顿。微信的朋友圈、淘宝的首页这种重量级页面,一次能抓几百个节点,展开全树卡到不行。我的经验是:先用左侧截图点击目标区域,让它自动定位到对应节点,然后只展开那一小段分支,比在树里一点一点找高效太多。
还有一种情况是 dump 不完全。比如某些页面里有弹窗或者正在播放的视频区域,dump 结果里可能只有部分节点,另外一部分节点动态渲染还没完成。处理方式是多截几次图,等页面完全静止后再抓。
5.3 特殊应用(Flutter/WebView/游戏)的应对思路
很多新 App 是 Flutter 或 React Native 开发的,它们的 UI 不是传统 View 体系。uiautomatorviewer 抓 Flutter 应用时,节点树往往非常“贫瘠”——可能只有一个FlutterView节点,下面没有任何子节点。
这不代表工具废了,而是 Flutter 的自绘机制摆在那里,系统无障碍层面拿不到控件级信息。这种情况下,有几个替代方案:
- 用 Flutter 官方的无障碍协议,或者专门的 Flutter 测试驱动引擎;
- 用 Appium 的 Flutter Driver 扩展;
- 直接退回坐标点击方案,从 UI 布局截图里人工确认按钮位置,用
adb shell input tap x y去交互。
WebView 混排也是高频场景。uiautomatorviewer 只能看到 WebView 节点,看不到网页内部元素。自动化测试里建议采用混合上下文切换,在 WebView 上下文中用前端定位方式来操作。
游戏类和自定义绘制类应用更直接,本质上整个屏幕就是一个大 View,uiautomatorviewer 拿到的可能只有 SurfaceView 或 TextureView 节点。做这类应用的 UI 测试,基本都是坐标模拟点击加图像识别,没有任何捷径。
6. 进阶玩法:把 UI dump 和自动化测试串起来
只会用鼠标点截图、看节点树,那还是停留在入门阶段。真正高效的做法是把 uiautomatorviewer 的结果拿到脚本里去用。
6.1 命令行 dump UI XML
uiautomatorviewer 图形界面背后,其实就是在设备上执行了uiautomator dump然后解析 XML。你完全可以在命令行里手动完成这件事:
adb shell uiautomator dump /sdcard/window_dump.xml adb pull /sdcard/window_dump.xml ./window_dump.xmlWindows 下也可以用adb exec-out uiautomator dump /dev/tty > dump.xml,但有些低版本设备不支持这个写法,还是走 sdcard 中转兼容性最好。
拿到 XML 后,你可以用 Python 的xml.etree.ElementTree解析所有节点,批量提取 text、resource-id、bounds。比如写一个脚本把所有按钮的中心点打印出来,生成一个页面元素清单。这对于做多页面自动化用例、维护 UI 元素档案特别有用。
6.2 和 Appium、Airtest 等框架的联动思路
uiautomatorviewer 抓出来的元素信息,和 Appium 等框架使用的定位策略是通用的。
- Appium 里
mobile: inspect本质上触达的信息源也是 accessibility 节点,所以你在 uiautomatorviewer 里看到resource-id、text的那套逻辑,搬到 Appium 的findElementById、findElementByText上完全成立。 - 如果拿到的
resource-id为空,直接改用 XPath,比如//android.widget.TextView[@text='登录']。 - 配合图像识别做兜底:坐标定位 +
adb shell input tap,能实现一种轻量级的“无依赖自动化”。
我个人的建议是:别把 uiautomatorviewer 当成唯一的分析工具,它更适合做前期的“侦察兵”。真正跑自动化回归时,还是要用能持续集成的框架,uiautomatorviewer 提供的是定位素材,不是执行引擎。
6.3 一个实用脚本示例:批量提取页面按钮坐标
这里给一个简单的 Python 脚本,解析 uiautomator dump 出的 XML,筛选出所有可点击节点并输出中心坐标:
import xml.etree.ElementTree as ET def center_from_bounds(bounds_str): # bounds 格式如 [108,1836][972,1980] parts = bounds_str.replace('[', '').replace(']', ',').split(',') left, top, right, bottom = map(int, parts) return (left + right) // 2, (top + bottom) // 2 tree = ET.parse('window_dump.xml') for node in tree.iter('node'): if node.get('clickable') == 'true': bounds = node.get('bounds') text = node.get('text') rid = node.get('resource-id') cx, cy = center_from_bounds(bounds) print(f'text={text} | id={rid} | 中心点=({cx},{cy})')这个脚本在我维护页面元素清单的时候很有用,几分钟就能把一整个页面的可点击元素全列出来。
7. 一点个人使用的经验总结
回到开头那个问题,为什么我还是愿意用 uiautomatorviewer 去分析微信、支付宝这类应用的 UI 布局?表面上是 Layout Inspector 不能用,更深层的原因是:uiautomatorviewer 基于无障碍机制的渲染方式,决定了它在任何普通第三方应用面前都稳定可用。它的界面虽然老,但该给的信息一个不少,而且导出 XML 的兼容性很好,方便我做后续自动化处理。
工具用得越久,我越觉得它更适合当“地基”。你想分析任意 App 的界面,用它;你想快速确认某个元素有没有resource-id,用它;你想在一堆节点里找一个控件的精确坐标,用它。等把这些基础信息摸清楚了,后续上 Appium、Airtest、或者自研的平台,心里都会很有底。
最后分享一个很实用的小技巧:分析某个 App 的时候,如果发现 uiautomatorviewer 抓出来的截图和真实界面有偏差,尤其是深色模式或者全屏页面,可以先在手机上把界面切到浅色模式,再抓一次。部分控件在深色背景下的文字对比度会影响视觉识别,但深色模式下的树结构和浅色模式下是基本一致的,浅色模式下更容易看清节点边界。抓完再切回深色模式,不影响定位结果。
如果你现在正被 Layout Inspector 的局限卡住,又拿微信、支付宝这类应用没辙,直接试试这条老路子,绝对会有豁然开朗的感觉。用熟了这套工具链,以后不管遇到什么 App 的界面分析需求,你都不会再慌。