• 就是 udid,亲测可行,
    如果是通过 wifiadb 连接的话 udid 就是类似于这种 172.18.101.150:5555
    如果是直接 usb 连接的话 就是 760BBKU229HU
    反正通过 adb devices 查看就可以了。如果不行,建议贴出 appium server 的 log

  • 你的 log 貌似截的不对哦,看 log 还是在 swipe,接着截屏都是没问题的,应该再截下面一些的 log。

  • #3 楼 @chenhengjie123 是不是说我二次开发的 apk 只要丢到 appium 的那个 setting 的路径下就可以了?

  • 把里面 self.去掉应该就没什么了,建议去看下 python 的基础。

  • #1 楼 @chenhengjie123 那回到开始的问题,appium 有办法能使 listview 滚到底部吗?

  • #9 楼 @jennyhui 说实话我也是没用过,今天中午研究了下,还真可以。我也学习了。

  • #2 楼 @cpfeng0124 为了验证刚才你说的 我重新试了下,如果服务端在远端,脚本里面配置远端的 IP 地址类似于 172.18.48.123
    那么 如果 Server Address 如果是 127.0.0.1 是不行的,只有改成本机的 IP 才可以。你在再验证实施。

  • 但是你输入 127.0.0.1 跟输入本机的 ip 地址是有区别的,类似于你的服务器放在云端,你的脚本放在本地,这个时候这个 serverAddress 就有用处了啊。

  • #7 楼 @jennyhui 我想说实际上加分号是可以的 只是 appium 做了些处理。
    我查找的代码如下

    driver.find_element_by_android_uiautomator('new UiSelector().resourceId("'+Id+'");new UiSelector().clickable(false)')
    

    接着看看 appium for windows 的 log

    实际上两条 selector 语句都是会执行的,但是问题来了为什么 log 打印还是采用

    Using: UiSelector[RESOURCE_ID=com.seewo.teachercare:id/pass_notice_list_add_notice_imageButton]
    

    这个呢,而忽略了我的后面那个 clickable 的 selector 实际上看 FIND 函数就知道了

    final List<UiSelector> selectors = getSelectors(strategy, text, multiple);
          if (!multiple) {
            for (int i = 0; i < selectors.size() && !found; i++) {
              try {
                Logger.debug("Using: " + selectors.get(i).toString());
                result = fetchElement(selectors.get(i), contextId);
                found = result != null;
              } catch (final ElementNotFoundException ignored) {
              }
            }
          }
    

    这里实际上查找按顺序来,如果找到的话 就赋值给了 found,接着 for 循环中如果 found 为空的情况下才会继续往下走,所以前面只是查找到 resoureID 就跳出来了,我估计分号的用法是个或的关系 即如果这种情况下找不到 再换另外一种 selector 进行查找为了验证这个 我换下我的查找

    driver.find_element_by_android_uiautomator('new UiSelector().className("hehe.hehe");new UiSelector().resourceId("'+Id+'")')
    

    这个时候看下 log 就一目了然了。

    结论:分号的用法是一个或的用法,前面成立的话后面就不执行了。

  • scrollTo 方法的一些问题 at 2015年08月07日

    #10 楼 @chenhengjie123

    好处是不仅能支持 Android(不过有点问题)是什么问题?
    感觉楼主说的貌似没错,看代码那么写,如果有第二个 scrollview 那就滑动不了了?

  • #5 楼 @jennyhui 有点明白了,但是我更疑惑的点是在于
    还是同一个段代码

    private void consumeStatement() throws UiSelectorSyntaxException {
       String statement;
       int index = 0;
       int parenCount = -1; // semicolons could appear inside String arguments, so we make sure we only count occurrences outside of a parenthesis pair
       while (index < text.length()) {
         if (text.charAt(index) == ';' && parenCount == 0) {
           break;
         }
         if (text.charAt(index) == '(') {
           if (parenCount < 0) {
             parenCount = 1;
           } else {
             parenCount++;
           }
         }
         if (text.charAt(index) == ')') {
           parenCount--;
         }
         index++;
       }
    
       statement = text.substring(0, index);
       if (UiScrollableParser.isUiScrollable(statement)) {
         Logger.debug("Parsing scrollable: " + statement);
         selectors.add(scrollableParser.parse(statement));
       } else {
         Logger.debug("Parsing selector: " + statement);
         selectors.add(selectorParser.parse(statement));
       }
    
       text = text.substring(index);
     }
    

    因为 selectors 是一个 List所以如果说存在有分号的话,那就应该会产生多个 selector 就是根据分号来进行划分的吧。
    难道说还可以有这种用法?

    driver.findElement(MobileBy.AndroidUIAutomator("new UiSelector().index(0);new UiSelector().checked(true)"));
    
  • #2 楼 @jennyhui
    重新又看了下源码,调试一步步走 大概知道了一些,这里只是说 Bootstrap 是如何执行到 UiSelectorParser
    首先看 appium windows 的 log

    可以知道的一点是 appium 发送给移动端的消息是

    ["find",{"strategy":"-android uiautomator","selector":"new UiSelector().resourceId(\"com.seewo.teachercare:id/pass_vote_body\")","context":"","multiple":false}]
    

    看 doctorq 关于 Bootstrap 的源码分析就可以的出来 这里的 ACTION 是 find,
    那就简单了 进到 Find.java 中看看就知道了。

    private AndroidCommandResult execute(final AndroidCommand command,
          final boolean isRetry) throws JSONException {
        final Hashtable<String, Object> params = command.params();
    
        // only makes sense on a device
        final Strategy strategy;
        try {
          strategy = Strategy.fromString((String) params.get("strategy"));
        } catch (final InvalidStrategyException e) {
          return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND, e.getMessage());
        }
    
        final String contextId = (String) params.get("context");
        final String text = (String) params.get("selector");
        final boolean multiple = (Boolean) params.get("multiple");
    
        Logger.debug("Finding " + text + " using " + strategy.toString()
            + " with the contextId: " + contextId + " multiple: " + multiple);
        boolean found = false;
        try {
          Object result = null;
          final List<UiSelector> selectors = getSelectors(strategy, text, multiple);
    

    我这里只是截取了部分,看到最后一句 getSelector 返回的是一个 List所以肯定是在 getSelectors 中进行查找的
    在看看 getSelectors

    private List<UiSelector> getSelectors(final Strategy strategy,
         final String text, final boolean many) throws InvalidStrategyException,
         ElementNotFoundException, UiSelectorSyntaxException,
         ParserConfigurationException, InvalidSelectorException {
       final List<UiSelector> selectors = new ArrayList<UiSelector>();
       UiSelector sel = new UiSelector();
    
       switch (strategy) {
         case XPATH:
           for (final UiSelector selector : getXPathSelectors(text, many)) {
             selectors.add(selector);
           }
           break;
         case CLASS_NAME:
           sel = sel.className(text);
           if (!many) {
             sel = sel.instance(0);
           }
           selectors.add(sel);
           break;
         case ID:
           // There are three types of ids on Android.
           // 1. resourceId (API >= 18)
           // 2. accessibility id (content description)
           // 3. strings.xml id
           //
           // If text is a resource id then only use the resource id selector.
           if (API_18) {
             if (resourceIdRegex.matcher(text).matches()) {
               sel = sel.resourceId(text);
               if (!many) {
                 sel = sel.instance(0);
               }
               selectors.add(sel);
               break;
             } else {
               // not a fully qualified resource id
               // transform "textToBeChanged" into:
               // com.example.android.testing.espresso.BasicSample:id/textToBeChanged
               // android:id/textToBeChanged
               // either it's prefixed with the app package or the android system page.
               String pkg = (String) params.get("pkg");
    
               if (pkg != null) {
                 sel = sel.resourceId(pkg + ":id/" + text);
                 if (!many) {
                   sel = sel.instance(0);
                 }
                 selectors.add(sel);
               }
    
               sel = sel.resourceId("android:id/" + text);
               if (!many) {
                 sel = sel.instance(0);
               }
               selectors.add(sel);
             }
           }
    
           // must create a new selector or the selector from
           // the resourceId search will cause problems
           sel = new UiSelector().description(text);
           if (!many) {
             sel = sel.instance(0);
           }
           selectors.add(sel);
    
           // resource id and content description failed to match
           // so the strings.xml selector is used
           final UiSelector stringsXmlSelector = stringsXmlId(many, text);
           if (stringsXmlSelector != null) {
             selectors.add(stringsXmlSelector);
           }
           break;
         case ACCESSIBILITY_ID:
           sel = sel.description(text);
           if (!many) {
             sel = sel.instance(0);
           }
           selectors.add(sel);
           break;
         case NAME:
           sel = new UiSelector().description(text);
           if (!many) {
             sel = sel.instance(0);
           }
           selectors.add(sel);
    
           sel = new UiSelector().text(text);
           if (!many) {
             sel = sel.instance(0);
           }
           selectors.add(sel);
           break;
         case ANDROID_UIAUTOMATOR:
           List<UiSelector> parsedSelectors;
           try {
             parsedSelectors = uiAutomatorParser.parse(text);
           } catch (final UiSelectorSyntaxException e) {
             throw new UiSelectorSyntaxException(
                 "Could not parse UiSelector argument: " + e.getMessage());
           }
    
           for (final UiSelector selector : parsedSelectors) {
             selectors.add(selector);
           }
    
           break;
         case LINK_TEXT:
         case PARTIAL_LINK_TEXT:
         case CSS_SELECTOR:
         default:
           throw new InvalidStrategyException("Sorry, we don't support the '"
               + strategy.getStrategyName() + "' locator strategy yet");
       }
    
       return selectors;
     }
    

    内容很多,但是我们只看我们需要的 也就是 Strategy 为 ANDROID_UIAUTOMATOR 的
    看到这里 就知道了 parsedSelectors = uiAutomatorParser.parse(text);
    调用了 uiAutomatorParser 的解析,剩下的就简单了,uiAutomatorParser 的工作先对传进来的参数做些处理 类似于去掉空格之类的再来就判断你的字符串是 new UiSelecotor 还是 new UiScrollable 分别到对应的地方进行解析
    不过这里还有个疑问,

    while (index < text.length()) {
         if (text.charAt(index) == ';' && parenCount == 0) {
           break;
         }
         if (text.charAt(index) == '(') {
           if (parenCount < 0) {
             parenCount = 1;
           } else {
             parenCount++;
           }
         }
         if (text.charAt(index) == ')') {
           parenCount--;
         }
         index++;
       }
    

    uiAutomatorParser 会判断文本内容中是否包含有';'这个又是干什么呢,

  • scrollTo 方法的一些问题 at 2015年08月06日

    #2 楼 @shu 那个 hard code 是在哪看到的

  • #66 楼 @darker50 其实不用反编译,google 搜下直接就可以下到源代码的。

  • #63 楼 @adfghzhang 其实我想知道你是怎么解决的。。

  • #10 楼 @carl 有点明白了,类似于 uiautomator 的截图就是通过 device 实现的吧。我当时一开始的想法也是通过 IDevice 进行操作的, 但是我去看了 IDevice 这个类了,没找到我需要的操作啊,难道说是需要用 executeShellCommand(String, IShellOutputReceiver) 这个方法吗?不太会,能够举个例子吗

  • #4 楼 @kilmer 嗯 是的。

  • #6 楼 @carl 没办法 花一天的时间匆匆忙忙写的,而且对 swt/jface 实际上我并不是很了解。
    另外你说的一点通过拿到的 idevice 可以做什么操作呢?

  • #1 楼 @chenhengjie123 是的 目前我做的就是每一个点击的操作做 writeFile,我觉得我写的还是比较麻烦。

  • #59 楼 @adfghzhang https://plus.google.com/108487870030743970488/posts/2TrMqs1ZGQv 这个链接网上说可以解决问题,但是我修改失败了 所以我直接修改 DebugBridge 中

    f (toolsDir == null) {
                toolsDir ="D:\\AndroidSDK\\android-sdk-windows\\android-sdk-windows\\tools";
    //          return null;;
            }
    

    就可以了