dim.red

View Hierarchy

背景

在脚本录制回放过程中, 我们需要获取 View Hierarchy 的意图有三个.

  • 将 View Hierarchy 结合 App 截图 发送给前端. 前端用这两个做可视化显示.
  • 在录制中.需要获取 View Hierarchy 遍历控件, 对控件进行监听.
  • 在回放中. 需要根据 View Hierarchy 找到 回放操作 对应的控件.

实现方式

实例1

方式一: activity onResume

原理: ContentView 在 Activity 的onResume 里添加到屏幕上.
优点: 实现简单
缺点: 获取的视图不全面. 类似Dialog , PopWindow
在 实例1 中只能获取 Activity 层级, 领圣诞礼卷的对话框就获取不到了.

方式二: hook LayoutInflater

原理: res 的 layout 资源通过 LayoutInflater 解析成 View.
优点: 覆盖了所有从layout资源里面加载的控件
缺点: 系统兼容性问题, 能兼容 90% 以上的情况.

方式三: hook WindowManager

原理: 一个View 要显示在屏幕上, 都需要调用 WindowManager.add(XX) 方法.
优点: 覆盖了所有情况
缺点: 系统兼容性问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
Class<?> windowManagerGlobal = Class.forName("android.view.WindowManagerGlobal");
Object windowManagerGlobalInstance = on(windowManagerGlobal).call("getInstance").get();
Object mViewsObject = on(windowManagerGlobalInstance).field("mViews").get();
Object mParamsObject = on(windowManagerGlobalInstance).field("mParams").get();
ArrayList<View> mViews = (ArrayList<View>) mViewsObject;
ArrayList<WindowManager.LayoutParams> mParams = (ArrayList<WindowManager.LayoutParams>) mParamsObject;
ObserverArrayList<View> observerArrayList = createViews();
ObserverArrayList<WindowManager.LayoutParams> paramsObserverArrayList = createParams();
observerArrayList.addAll(mViews);
paramsObserverArrayList.addAll(mParams);
on(windowManagerGlobalInstance).set("mViews", observerArrayList);
on(windowManagerGlobalInstance).set("mParams", paramsObserverArrayList);
} catch (Exception e) {
e.printStackTrace();
}