<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)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲精品偷拍视频免费观看| 三年片免费高清版| 亚洲精品国产va在线观看蜜芽| 国产成人无码精品久久久久免费| 亚洲国产精品婷婷久久| 午夜成人免费视频| a视频在线免费观看| 亚洲av乱码一区二区三区香蕉 | 极品美女一级毛片免费| 亚洲av伊人久久综合密臀性色| 无码日韩人妻av一区免费| aa午夜免费剧场| 亚洲精品天堂在线观看| 亚洲综合日韩久久成人AV| 毛片视频免费观看| 国产精品免费无遮挡无码永久视频| 亚洲男人的天堂久久精品| 国产亚洲人成A在线V网站| 成人免费视频网址| 亚在线观看免费视频入口| 激情小说亚洲色图| 亚洲图片校园春色| 日本亚洲视频在线| 免费人成视频x8x8入口| 99久久精品日本一区二区免费| 一级毛片免费毛片毛片| 亚洲午夜福利在线视频| 亚洲酒色1314狠狠做| 国产日韩成人亚洲丁香婷婷| 免费高清在线爱做视频| 中文字幕免费在线观看| a级片免费观看视频| 男女污污污超污视频免费在线看| 亚洲AV无码专区在线亚| 亚洲影院在线观看| 亚洲精品国产精品乱码不卡√| 四虎永久成人免费| 免费爱爱的视频太爽了| 国产一精品一AV一免费孕妇 | 国产高清在线免费| 国产无人区码卡二卡三卡免费 |