MonkenRunner通过HierarchyViewer定位控件的方法和建议(Appium/UIAutomator/Robotium姊妹篇)
1. 背景
在使用MonkeyRunner的时候我们经常会用到Chimchat下面的HierarchyViewer模块来获取目标控件的一些信息来辅助我们测试,但在MonkeyRunner的官网上是没有看到相应的API的描述的,上面只有以下三个类的API引用信息(http://developer.android.com/tools/help/MonkeyDevice.html)
- MonkeyDevice
- MonkeyImage
- MonkeyRunner
2.findViewById(String id)
2.1 示例
targetDevice = MonkeyRunner.waitForConnection() ‘‘‘ public ViewNode findViewById(String id) * @param id id for the view. * @return view with the specified ID, or {@code null} if no view found. ‘‘‘ viewer = targetDevice.getHierarchyViewer() button = viewer.findViewById(‘id/title‘) text = viewer.getText(button) print text.encode(‘utf-8‘)
2.2 分析和建议
- 一旦MonkeyRunner连接上设备,会立刻获得一个MonkeyDevice的对象代表了目标测试设备,我们就是通过这个设备对象来控制设备的
- 注意这里需要填写的id的格式和UIAutomatorViewer获得ResourceId是不一样的,请看下图UIAutomatorViewer截图中ResourceId前面多出了"android:"字串:
- 这个方法返回的一个ViewNode的对象,代表目标控件,拥有大量控件相关的属性,由于篇幅问题这里不详述,往后应该会另外撰文描述它的使用。在本文里知道它代表了目标控件就行了
- 最后打印的时候需要转换成UTF-8编码的原因跟Jython默认的编码格式有关系,具体描述和Workaround请查看:http://www.haogongju.net/art/1636997
3. findViewById(String id, ViewNode rootNode)
3.1示例
‘‘‘ public ViewNode findViewById(String id, ViewNode rootNode) * Find a view by ID, starting from the given root node * @param id ID of the view you‘re looking for * @param rootNode the ViewNode at which to begin the traversal * @return view with the specified ID, or {@code null} if no view found. ‘‘‘ iconMenuView = viewer.findViewById(‘id/icon_menu‘) button = viewer.findViewById(‘id/title‘,iconMenuView) print "Button Text:",text.encode(‘utf-8‘)
3.2分析
4 getAbsolutePositionOfView(ViewNode node)
4.1示例
‘‘‘ public static Point getAbsoluteCenterOfView(ViewNode node) * Gets the absolute x/y center of the specified view node. * * @param node view node to find position of. * @return absolute x/y center of the specified view node. */ ‘‘‘ point = viewer.getAbsoluteCenterOfView(button) print "Button Absolute Center Position:",point
4.2 分析和建议
5. getAbsoluteCenterOfView(ViewNode node)
5.1 示例
‘‘‘ public static Point getAbsoluteCenterOfView(ViewNode node) * Gets the absolute x/y center of the specified view node. * * @param node view node to find position of. * @return absolute x/y center of the specified view node. */ ‘‘‘ point = viewer.getAbsoluteCenterOfView(button) print "Button Absolute Center Position:",point
5.2 分析和建议
6. getFocusedWindowName()
6.1 示例
‘‘‘ public String getFocusedWindowName() * Gets the window that currently receives the focus. * * @return name of the window that currently receives the focus. ‘‘‘ window = viewer.getFocusedWindowName() print "Window Name:",window.encode(‘utf-8‘)
6.2 解析
7. visible(ViewNode node)
7.1 示例
‘‘‘ public boolean visible(ViewNode node) * Gets the visibility of a given element. * @param selector selector for the view. * @return True if the element is visible. ‘‘‘ isVisible = viewer.visible(button) print "is visible:",isVisible就是查看下控件是否可见,没什么好解析的了。
8. 测试代码
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice from com.android.monkeyrunner.easy import EasyMonkeyDevice,By from com.android.chimpchat.hierarchyviewer import HierarchyViewer from com.android.hierarchyviewerlib.models import ViewNode, Window from java.awt import Point #from com.android.hierarchyviewerlib.device import #Connect to the target targetDevice targetDevice = MonkeyRunner.waitForConnection() easy_device = EasyMonkeyDevice(targetDevice) #touch a button by id would need this targetDevice.startActivity(component="com.example.android.notepad/com.example.android.notepad.NotesList") #time.sleep(2000) #invoke the menu options MonkeyRunner.sleep(6) targetDevice.press(‘KEYCODE_MENU‘, MonkeyDevice.DOWN_AND_UP); ‘‘‘ public ViewNode findViewById(String id) * @param id id for the view. * @return view with the specified ID, or {@code null} if no view found. ‘‘‘ viewer = targetDevice.getHierarchyViewer() button = viewer.findViewById(‘id/title‘) text = viewer.getText(button) print text.encode(‘utf-8‘) ‘‘‘ public ViewNode findViewById(String id, ViewNode rootNode) * Find a view by ID, starting from the given root node * @param id ID of the view you‘re looking for * @param rootNode the ViewNode at which to begin the traversal * @return view with the specified ID, or {@code null} if no view found. ‘‘‘ iconMenuView = viewer.findViewById(‘id/icon_menu‘) button = viewer.findViewById(‘id/title‘,iconMenuView) print "Button Text:",text.encode(‘utf-8‘) ‘‘‘ public String getFocusedWindowName() * Gets the window that currently receives the focus. * * @return name of the window that currently receives the focus. ‘‘‘ window = viewer.getFocusedWindowName() print "Window Name:",window.encode(‘utf-8‘) ‘‘‘ public static Point getAbsoluteCenterOfView(ViewNode node) * Gets the absolute x/y center of the specified view node. * * @param node view node to find position of. * @return absolute x/y center of the specified view node. */ ‘‘‘ point = viewer.getAbsoluteCenterOfView(button) print "Button Absolute Center Position:",point ‘‘‘ public static Point getAbsolutePositionOfView(ViewNode node) * Gets the absolute x/y position of the view node. * * @param node view node to find position of. * @return point specifying the x/y position of the node. ‘‘‘ point = viewer.getAbsolutePositionOfView(button) print "Button Absolute Position:", point ‘‘‘ public boolean visible(ViewNode node) * Gets the visibility of a given element. * @param selector selector for the view. * @return True if the element is visible. ‘‘‘ isVisible = viewer.visible(button) print "is visible:",isVisible
9.附上HierarchyViewer类的源码方便参照
/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.chimpchat.hierarchyviewer; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.hierarchyviewerlib.device.DeviceBridge; import com.android.hierarchyviewerlib.device.ViewServerDevice; import com.android.hierarchyviewerlib.models.ViewNode; import com.android.hierarchyviewerlib.models.Window; import org.eclipse.swt.graphics.Point; /** * Class for querying the view hierarchy of the device. */ public class HierarchyViewer { public static final String TAG = "hierarchyviewer"; private IDevice mDevice; /** * Constructs the hierarchy viewer for the specified device. * * @param device The Android device to connect to. */ public HierarchyViewer(IDevice device) { this.mDevice = device; setupViewServer(); } private void setupViewServer() { DeviceBridge.setupDeviceForward(mDevice); if (!DeviceBridge.isViewServerRunning(mDevice)) { if (!DeviceBridge.startViewServer(mDevice)) { // TODO: Get rid of this delay. try { Thread.sleep(2000); } catch (InterruptedException e) { } if (!DeviceBridge.startViewServer(mDevice)) { Log.e(TAG, "Unable to debug device " + mDevice); throw new RuntimeException("Could not connect to the view server"); } return; } } DeviceBridge.loadViewServerInfo(mDevice); } /** * Find a view by id. * * @param id id for the view. * @return view with the specified ID, or {@code null} if no view found. */ public ViewNode findViewById(String id) { ViewNode rootNode = DeviceBridge.loadWindowData( new Window(new ViewServerDevice(mDevice), "", 0xffffffff)); if (rootNode == null) { throw new RuntimeException("Could not dump view"); } return findViewById(id, rootNode); } /** * Find a view by ID, starting from the given root node * @param id ID of the view you‘re looking for * @param rootNode the ViewNode at which to begin the traversal * @return view with the specified ID, or {@code null} if no view found. */ public ViewNode findViewById(String id, ViewNode rootNode) { if (rootNode.id.equals(id)) { return rootNode; } for (ViewNode child : rootNode.children) { ViewNode found = findViewById(id,child); if (found != null) { return found; } } return null; } /** * Gets the window that currently receives the focus. * * @return name of the window that currently receives the focus. */ public String getFocusedWindowName() { int id = DeviceBridge.getFocusedWindow(mDevice); Window[] windows = DeviceBridge.loadWindows(new ViewServerDevice(mDevice), mDevice); for (Window w : windows) { if (w.getHashCode() == id) return w.getTitle(); } return null; } /** * Gets the absolute x/y position of the view node. * * @param node view node to find position of. * @return point specifying the x/y position of the node. */ public static Point getAbsolutePositionOfView(ViewNode node) { int x = node.left; int y = node.top; ViewNode p = node.parent; while (p != null) { x += p.left - p.scrollX; y += p.top - p.scrollY; p = p.parent; } return new Point(x, y); } /** * Gets the absolute x/y center of the specified view node. * * @param node view node to find position of. * @return absolute x/y center of the specified view node. */ public static Point getAbsoluteCenterOfView(ViewNode node) { Point point = getAbsolutePositionOfView(node); return new Point( point.x + (node.width / 2), point.y + (node.height / 2)); } /** * Gets the visibility of a given element. * * @param selector selector for the view. * @return True if the element is visible. */ public boolean visible(ViewNode node) { boolean ret = (node != null) && node.namedProperties.containsKey("getVisibility()") && "VISIBLE".equalsIgnoreCase( node.namedProperties.get("getVisibility()").value); return ret; } /** * Gets the text of a given element. * * @param selector selector for the view. * @return the text of the given element. */ public String getText(ViewNode node) { if (node == null) { throw new RuntimeException("Node not found"); } ViewNode.Property textProperty = node.namedProperties.get("text:mText"); if (textProperty == null) { // give it another chance, ICS ViewServer returns mText textProperty = node.namedProperties.get("mText"); if (textProperty == null) { throw new RuntimeException("No text property on node"); } } return textProperty.value; } }
10. 参考阅读
作者 | 自主博客 | 微信服务号及扫描码 | CSDN |
天地会珠海分舵 | http://techgogogo.com | 服务号:TechGoGoGo扫描码: | http://blog.csdn.net/zhubaitian |
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。