<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    Appium Android Bootstrap源碼分析之命令解析執行

    通過上一篇文章Appium Android Bootstrap源碼分析之控件AndroidElement》我們知道了Appium從pc端發送過來的命令如果是控件相關的話,最終目標控件在bootstrap中是以AndroidElement對象的方式呈現出來的,并且該控件對象會在AndroidElementHash維護的控件哈希表中保存起來。但是appium觸發一個命令除了需要提供是否與控件相關這個信息外,還需要其他的一些信息,比如,這個是什么命令?這個就是我們這篇文章需要討論的話題了。
      下面我們還是先看一下從pc端發過來的json的格式是怎么樣的:
      可以看到里面除了params指定的是哪一個控件之外,還指定了另外兩個信息:
      cmd: 這是一個action還是一個shutdown
      action:如果是一個action的話,那么是什么action
      開始前我們先簡要描述下我們需要涉及到幾個關鍵類:
    1. Appium命令解析器AndroidCommand
      AndroidCommand這個類真實的作用其實就是去把Appium從pc端發送過來的那串json命令解析出來,它擁有兩個成員變量:
      JSONObject         json;
      AndroidCommandType cmdType;
      json就是pc過來的json格式的那串命令,cmdType就是action或者shutdown,其實就是用來把這個類偽裝成更像個命令類而已,我認為如果不提供這個成員變量而直接修改其getType的實現去解析json字串直接獲得對應的AndroidCommandType,然后把這個類的名字改成AndroidCommandParser得了。
      那么我們往下看下AndroidCommand究竟是怎么對客戶端命令進行解析的,它的方法都很短,所以我把它做成一個表,這樣比較清晰點:
      從表中的這些方法可以看出來,這個類所做的事情基本上都是怎么去解析appium從pc端過來的那串json字串。

      2. Action與CommandHandler的映射關系
      從上面描述可以知道,一個action就是一個代表該命令的字串,比如‘click’。但是一個字串是不能去執行的啊,所以我們需要有一種方式把它轉換成可以執行的代碼,這個就是AndroidCommandExecutor維護的一個靜態HashMap map所做的事情:
    class AndroidCommandExecutor {
    private static HashMap<String, CommandHandler> map = new HashMap<String, CommandHandler>();
    static {
    map.put("waitForIdle", new WaitForIdle());
    map.put("clear", new Clear());
    map.put("orientation", new Orientation());
    map.put("swipe", new Swipe());
    map.put("flick", new Flick());
    map.put("drag", new Drag());
    map.put("pinch", new Pinch());
    map.put("click", new Click());
    map.put("touchLongClick", new TouchLongClick());
    map.put("touchDown", new TouchDown());
    map.put("touchUp", new TouchUp());
    map.put("touchMove", new TouchMove());
    map.put("getText", new GetText());
    map.put("setText", new SetText());
    map.put("getName", new GetName());
    map.put("getAttribute", new GetAttribute());
    map.put("getDeviceSize", new GetDeviceSize());
    map.put("scrollTo", new ScrollTo());
    map.put("find", new Find());
    map.put("getLocation", new GetLocation());
    map.put("getSize", new GetSize());
    map.put("wake", new Wake());
    map.put("pressBack", new PressBack());
    map.put("pressKeyCode", new PressKeyCode());
    map.put("longPressKeyCode", new LongPressKeyCode());
    map.put("takeScreenshot", new TakeScreenshot());
    map.put("updateStrings", new UpdateStrings());
    map.put("getDataDir", new GetDataDir());
    map.put("performMultiPointerGesture", new MultiPointerGesture());
    map.put("openNotification", new OpenNotification());
    map.put("source", new Source());
    map.put("compressedLayoutHierarchy", new CompressedLayoutHierarchy());
    }
      這個map指定了我們支持的pc端過來的所有action,以及對應的處理該action的類的實例,其實這些類都是CommandHandler的子類基本上就只有一個:去實現CommandHandler的虛擬方法execute!要做的事情就大概就這幾類:
      控件相關的action:調用AndroidElement控件的成員變量UiObject el對應的方法來執行真實的操作
      UiDevice相關的action:調用UiDevice提供的方法
      UiScrollable相關的action:調用UiScrollable提供的方法
      UiAutomator那5個對象都沒有的action:該調用InteractionController的就反射調用,該調用QueryController的就反射調用。注意這兩個類UiAutomator是沒有提供直接調用的方法的,所以只能通過反射。更多這兩個類的信息請翻看之前的UiAutomator源碼分析相關的文章
      其他:如取得compressedLayoutHierarchy
      指導action向CommandHandler真正發生轉換的地方是在這個AndroidCommandExecutor的execute方法中:
    public AndroidCommandResult execute(final AndroidCommand command) {
    try {
    Logger.debug("Got command action: " + command.action());
    if (map.containsKey(command.action())) {
    return map.get(command.action()).execute(command);
    } else {
    return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND,
    "Unknown command: " + command.action());
    }
    } catch (final JSONException e) {
    Logger.error("Could not decode action/params of command");
    return new AndroidCommandResult(WDStatus.JSON_DECODER_ERROR,
    "Could not decode action/params of command, please check format!");
    }
    }
      它首先叫上面的AndroidCommand解析器把json字串的action給解析出來
      然后通過剛提到的map把這個action對應的CommandHandler的實現類給實例化
      然后調用這個命令處理類的execute方法開始執行命令
      3. 命令處理示例
      我們這里就示例性的看下getText這個action對應的CommandHandler是怎么去通過AndroidElement控件進行設置文本的處理的:
    public class GetText extends CommandHandler {
    /*
    * @param command The {@link AndroidCommand} used for this handler.
    *
    * @return {@link AndroidCommandResult}
    *
    * @throws JSONException
    *
    * @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.
    * bootstrap.AndroidCommand)
    */
    @Override
    public AndroidCommandResult execute(final AndroidCommand command)
    throws JSONException {
    if (command.isElementCommand()) {
    // Only makes sense on an element
    try {
    final AndroidElement el = command.getElement();
    return getSuccessResult(el.getText());
    } catch (final UiObjectNotFoundException e) {
    return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,
    e.getMessage());
    } catch (final Exception e) { // handle NullPointerException
    return getErrorResult("Unknown error");
    }
    } else {
    return getErrorResult("Unable to get text without an element.");
    }
    }
    }
      關鍵代碼就是里面通過AndroidCommand的getElement方法:
      解析傳進來的AndroidCommand實例保存的pc端過來的json字串,找到’params‘項的子項’elementId'
      通過這個獲得的id去控件哈希表(請查看《Appium Android Bootstrap源碼分析之控件AndroidElement》)中找到目標AndroidElement控件對象
      然后調用獲得的AndroidElement控件對象的getText方法:
      最終通過調用AndroidElement控件成員UiObject控件對象的getText方法取得控件文本信息
      4. 小結
      bootstrap接收到appium從pc端發送過來的json格式的鍵值對字串有多個項:
      cmd: 這是一個action還是一個shutdown
      action:如果是一個action的話,那么是什么action,比如click
      params:擁有其他的一些子項,比如指定操作控件在AndroidElementHash維護的控件哈希表的控件鍵值的'elementId'
      在收到這個json格式命令字串后:
      AndroidCommandExecutor會調用AndroidCommand去解析出對應的action
      然后把action去map到對應的真實命令處理方法CommandHandler的實現子類對象中
      然后調用對應的對象的execute方法來執行命令
    相關文章:
    Appium Android Bootstrap源碼分析之簡介
    Appium Android Bootstrap之控件AndroidElement

    posted on 2014-12-23 00:25 順其自然EVO 閱讀(2951) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄 、android

    <2014年12月>
    30123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲三级高清免费| 亚洲导航深夜福利| av成人免费电影| 亚洲精品无码成人片在线观看 | 日本免费电影一区| 亚洲av综合av一区二区三区| 午夜无遮挡羞羞漫画免费| 亚洲一区二区三区成人网站| 丁香花免费完整高清观看| 亚洲一区中文字幕在线观看| 中文字幕人成无码免费视频| 亚洲色无码国产精品网站可下载| 色www永久免费视频| 国产成人亚洲精品91专区高清| 一本色道久久88综合亚洲精品高清| 特级毛片aaaa免费观看| 久久亚洲中文字幕精品一区| 玖玖在线免费视频| 亚洲成a人片在线网站| 成人人免费夜夜视频观看| 男性gay黄免费网站| 亚洲熟妇无码八AV在线播放| 久久国产乱子伦精品免费不卡| 亚洲在成人网在线看| 日本xxwwxxww在线视频免费| 一区二区在线视频免费观看| 久久精品视频亚洲| 无码人妻一区二区三区免费手机| 亚洲av日韩综合一区二区三区| 久久精品国产精品亚洲| 1000部拍拍拍18勿入免费视频下载| 亚洲卡一卡二卡乱码新区| 亚洲精品视频在线看| 1000部啪啪未满十八勿入免费| 亚洲日本中文字幕天天更新| 丝袜熟女国偷自产中文字幕亚洲| **毛片免费观看久久精品| 婷婷国产偷v国产偷v亚洲| 亚洲AV天天做在线观看| 国产精品深夜福利免费观看| 成人网站免费看黄A站视频|