zoukankan      html  css  js  c++  java
  • UiAutomator源码学习(3)-- UiObject

    UiAutomator是由谷歌在Android4.1版本发布时推出的一款用Java编写的UI自动化测试框架。
    基于Accessibility服务,该工具提供了对外开放的的api,可以使用这些api对安卓应用进行一系列的自动化测试操作。例如:打开app、点击、滑动、键盘输入、长按以及常用的断言等一系列模拟ui操作。

    UiAutomator是Android自动化测试框架,其最大的特点就是可以跨进程操作,基本用法:

    device = UiDevice.getInstance(getInstrumentation());
     device.pressHome();
    
        // Bring up the default launcher by searching for a UI component
        // that matches the content description for the launcher button.
     UiObject allAppsButton = device
                .findObject(new UiSelector().description("Apps"));
    
        // Perform a click on the button to load the launcher.
     allAppsButton.clickAndWaitForNewWindow();
    UiDevice提供了很多操作的接口,在上一章介绍过。本章介绍UIObject和UiSelector
    UiObject代表了Android应用中定义的任意的View控件,可以根据
    UiSelector属性在运行时找到匹配的视图,可以对应不同的view。由此可以看出UIObject是视图对象,UiSelector是获取视图对象的匹配规则。
    看在UiDevice中的findObject方法:
      /**
         * Returns a UiObject which represents a view that matches the specified selector criteria.
         *
         * @param selector
         * @return UiObject object
         */
        public UiObject findObject(UiSelector selector) {
            return new UiObject(this, selector);
        }

    这个findObject方法返回了一个 UIObject对象,看UIObject的构造函数:

     /**
         * Package-private constructor. Used by {@link UiDevice#findObject(UiSelector)} to construct a
         * UiObject.
         */
        UiObject(UiDevice device, UiSelector selector) {
            mDevice = device;
            mUiSelecto

    这是一个包内可见的构造函数,所以如果我们想自己new UIObject,就会提示

    'UiObject(androidx.test.uiautomator.UiDevice, androidx.test.uiautomator.UiSelector)' is not public in 'androidx.test.uiautomator.UiObject'. Cannot be accessed from outside package

    所以我们只能用UiDevice通过UiSelector去查找界面中的UIObject。在UIObject这个类中我们也可以看到有获取UIObject属性的方法,如:

     /**
         * Retrieves the <code>className</code> property of the UI element.
         *
         * @return class name of the current node represented by this UiObject
         * @throws UiObjectNotFoundException if no match was found
         * @since API Level 18
         */
        public String getClassName() throws UiObjectNotFoundException {
            Tracer.trace();
            AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
            if(node == null) {
                throw new UiObjectNotFoundException(mUiSelector.toString());
            }
            String retVal = safeStringReturn(node.getClassName());
            Log.d(LOG_TAG, String.format("getClassName() = %s", retVal));
            return retVal;
        }
           AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
    方法里调用的是QueryController中的方法findAccessibilityNodeInfo(getSelector());

     在这个方法中有一个同步的代码块查找根节点:

     synchronized (mLock) {
                AccessibilityNodeInfo rootNode = getRootNode();
                if (rootNode == null) {
                    Log.e(LOG_TAG, "Cannot proceed when root node is null. Aborted search");
                    return null;
                }
                // Copy so that we don't modify the original's sub selectors
                UiSelector uiSelector = new UiSelector(selector);
                return translateCompoundSelector(uiSelector, rootNode, isCounting);
            }

    这里是UiAutomator得到节点的核心方法。

    getRootNode()最终调用的是UiAutomation的getRootInActiveWindow方法(与AccessibilityService交互)来获取根节点rootNode。根节点获取之后,通过递归

    translateCompoundSelector遍历 子节点。
     1  /**
     2      * A compoundSelector encapsulate both Regular and Pattern selectors. The formats follows:
     3      * <p/>
     4      * regular_selector = By[attributes... CHILD=By[attributes... CHILD=By[....]]]
     5      * <br/>
     6      * pattern_selector = ...CONTAINER=By[..] PATTERN=By[instance=x PATTERN=[regular_selector]
     7      * <br/>
     8      * compound_selector = [regular_selector [pattern_selector]]
     9      * <p/>
    10      * regular_selectors are the most common form of selectors and the search for them
    11      * is straightforward. On the other hand pattern_selectors requires search to be
    12      * performed as in regular_selector but where regular_selector search returns immediately
    13      * upon a successful match, the search for pattern_selector continues until the
    14      * requested matched _instance_ of that pattern is matched.
    15      * <p/>
    16      * Counting UI objects requires using pattern_selectors. The counting search is the same
    17      * as a pattern_search however we're not looking to match an instance of the pattern but
    18      * rather continuously walking the accessibility node hierarchy while counting matched
    19      * patterns, until the end of the tree.
    20      * <p/>
    21      * If both present, order of parsing begins with CONTAINER followed by PATTERN then the
    22      * top most selector is processed as regular_selector within the context of the previous
    23      * CONTAINER and its PATTERN information. If neither is present then the top selector is
    24      * directly treated as regular_selector. So the presence of a CONTAINER and PATTERN within
    25      * a selector simply dictates that the selector matching will be constraint to the sub tree
    26      * node where the CONTAINER and its child PATTERN have identified.
    27      * @param selector
    28      * @param fromNode
    29      * @param isCounting
    30      * @return AccessibilityNodeInfo
    31      */
    32     private AccessibilityNodeInfo translateCompoundSelector(UiSelector selector,
    33             AccessibilityNodeInfo fromNode, boolean isCounting) {
    34         // Start translating compound selectors by translating the regular_selector first
    35         // The regular_selector is then used as a container for any optional pattern_selectors
    36         // that may or may not be specified.
    37         if(selector.hasContainerSelector())
    38             // nested pattern selectors
    39             if(selector.getContainerSelector().hasContainerSelector()) {
    40                 fromNode = translateCompoundSelector(
    41                         selector.getContainerSelector(), fromNode, false);
    42                 initializeNewSearch();
    43             } else
    44                 fromNode = translateReqularSelector(selector.getContainerSelector(), fromNode);
    45         else
    46             fromNode = translateReqularSelector(selector, fromNode);
    47         if(fromNode == null) {
    48             if (DEBUG)
    49                 Log.d(LOG_TAG, "Container selector not found: " + selector.dumpToString(false));
    50             return null;
    51         }
    52         if(selector.hasPatternSelector()) {
    53             fromNode = translatePatternSelector(selector.getPatternSelector(),
    54                     fromNode, isCounting);
    55             if (isCounting) {
    56                 Log.i(LOG_TAG, String.format(
    57                         "Counted %d instances of: %s", mPatternCounter, selector));
    58                 return null;
    59             } else {
    60                 if(fromNode == null) {
    61                     if (DEBUG)
    62                         Log.d(LOG_TAG, "Pattern selector not found: " +
    63                                 selector.dumpToString(false));
    64                     return null;
    65                 }
    66             }
    67         }
    68         // translate any additions to the selector that may have been added by tests
    69         // with getChild(By selector) after a container and pattern selectors
    70         if(selector.hasContainerSelector() || selector.hasPatternSelector()) {
    71             if(selector.hasChildSelector() || selector.hasParentSelector())
    72                 fromNode = translateReqularSelector(selector, fromNode);
    73         }
    74         if(fromNode == null) {
    75             if (DEBUG)
    76                 Log.d(LOG_TAG, "Object Not Found for selector " + selector);
    77             return null;
    78         }
    79         Log.i(LOG_TAG, String.format("Matched selector: %s <<==>> [%s]", selector, fromNode));
    80         return fromNode;
    81     }
    遍历的条件是selector.hasContainerSelector(),UiSelector稍后会详细的解读。

    在UiObject中,还有对对象的操作方法,如click swipe等.这些方法调用的和UiDevice中的方法一样,都是

    getAutomatorBridge().getInteractionController().clickNoSync(x, y);如果不一样可能也是多了一些超时参数之类的重载方法。
    所以之后的流程可以参考上篇 UiDevice的解读,这里不再复述。
    UiDevice: https://www.cnblogs.com/yuan1225/p/13254235.html
  • 相关阅读:
    hdu 1151
    DAG的最小路径覆盖和二分图的最大匹配
    二部图 最小点覆盖集与最大匹配的关系
    sdut 2151
    sdut Emergency
    作业
    Node.prototype.contains
    微博登录
    markdown
    Object.observe
  • 原文地址:https://www.cnblogs.com/yuan1225/p/13272735.html
Copyright © 2011-2022 走看看