打造专属 uiautomatorviewer
由 uiautomator 二次开发得到的启发以及完善
uiautomatorviewer 二次开发之自动生成控件定位符
> PS 源码是@xuxu 分享的,对比了其他几位前辈的,貌似缺了几个文件和图标,但没什么太大影响
另外给大伙贴个uiautomatorviewer的源码:
https://android.googlesource.com/platform/frameworks/testing/+/aecdc4a/uiautomator/utils/uiautomatorviewer/src/com/android/uiautomator
需要导入的依赖包在eclipse/plugins
org.eclipse.core.commands_XXXXXX.jar
org.eclipse.equinox.common_XXXXXXX.jar
org.eclipse.jface_XXXXXXXX.jar
org.eclipse.swt.win32.win32.x86_64_XXXXXX.jar
### 功能点
- 新增清除操作按钮
![](/photo/2016/bcb90d382f627cddd40574ba5c1512b5.png)
- Activity & xpth属性
![](/photo/2016/f541e7493d679a2facf1b646fe96b618.png)
- 右键菜单
- Click
- Sendkey(根据输入值,自动生成Sendkey脚本语言)
- findElementBy (输入id或者class,返回符合要求的控件坐标。。。本来想标红的,无奈一直不成功)
- 鼠标点击事件
- sleep(根据输入值,自动生成sleep脚本语言)
- 输入字符到输入框(仍有bug,adb无法输入中文 && 手机输入法影响)
![](/photo/2016/e84aebec2a3c14cad07090c86c936d1b.png)
![](/photo/2016/1e2c27da6a3ffab03db2143632e0c89d.png)
![](/photo/2016/b2bd71fc4d53739a6d55b0359d962178.png)
![](/photo/2016/9526352ff5fe283cc18b0064a19f1220.png)
- 扩展展示界面(显示内容过多时,点击清除操作按钮后清除显示的内容)
![](/photo/2016/0029f4f4c53e88b878e5ec24d9603531.png)
### 其他
这些扩展功能,参考里面的前辈基本都已经说过了,我在做的时候花的时间也主要是SWT上,这也只是我之前从未接触过Java图形编程的原因,查文档花的时间比较多,所以也就不赘述了。
所以讲下 [打造专属 uiautomatorviewer](https://testerhome.com/topics/4614) 中,@zengjunzhou 前辈提到的
> 控件的id或text或content-desc或class相同,能不能区分选中的控件是第几个?
- 简单思路:
- 获取父节点和选中的节点
- 获取父节点下一级子节点
- 遍历子节点,对选中的节点左侧的子节点进行递归遍历,把结果并写入List
下面是我代码实现部分
#### 获取子节点
```java
/**
* 返回需要的节点数组
* @param parentNode 父节点
* @param selectedNode 当前选中的节点
* @return
*/
public static List<BasicTreeNode> AllChildNodes(BasicTreeNode parentNode, BasicTreeNode selectedNode){
//某个父节点下的所有子节点
List<BasicTreeNode> childNodes = new ArrayList<BasicTreeNode>();
Recursion(parentNode, selectedNode, childNodes);
return childNodes;
}
/**
* 简单的一个递归获取需要的子节点
* @param currentNode 父节点
* @param selectedNode 当前选中的节点
* @param childList 存储的子节点数组
*/
public static void Recursion(BasicTreeNode currentNode, BasicTreeNode selectedNode, List<BasicTreeNode> childList){
if (currentNode.hasChild()) {
for (BasicTreeNode temp : currentNode.getChildren()) {
if (!temp.equals(selectedNode)) {
childList.add(temp);
if (temp.hasChild()) {
Recursion(temp, selectedNode, childList);
}
else {
continue;
}
}
else {
break;
}
}
}
}
//class
MenuItem classInputItem = new MenuItem(inputChridItem, SWT.PUSH);
classInputItem.setText("class");
classInputItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e){
UiNode sele = (UiNode) UiAutomatorModel.getModel().getSelectedNode();
String classSele = sele.getAttribute("class");
InputDialog dialog = new InputDialog(getShell(), "请输入文本", "请输入", null, null);
String value = "";
if (dialog.open() == InputDialog.OK) {
value = dialog.getValue();
// System.out.println(value);
String ursClass = "driver.findElementById(\"" + classSele + "\").sendKeys(\"" + value + "\");";
System.out.println(ursClass);
}
int num = 0;
boolean flag = true;
BasicTreeNode parent = UiAutomatorModel.getModel().getSelectedNode().getParent();
List<BasicTreeNode> childNodes = BasicTreeNode.AllChildNodes(parent, UiAutomatorModel.getModel().getSelectedNode());
for (int i = 0; i < childNodes.size(); i++) {
BasicTreeNode temp = childNodes.get(i);
UiNode tempUinode = (UiNode) temp;
if (tempUinode.getAttribute("class").equals(classSele)) {
num++;
flag = false;
}
}
if (flag) {
String ursClass = "driver.findElementByClassName(\"" + classSele + "\").sendKeys(\"" + value + "\");" + "\n";
System.out.println(ursClass);
show += ursClass;
text.setText(show);
}
else {
String ursClasses = "driver.findElementsByClassName(\"" + classSele + "\").get(" + num + "\").sendKeys(\"" + value + "\");" + "\n";
System.out.println(ursClasses);
show += ursClasses;
text.setText(show);
}
}
});