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

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

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

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

    Appium Android Bootstrap源碼分析之命令解析執(zhí)行

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

      2. Action與CommandHandler的映射關(guān)系
      從上面描述可以知道,一個(gè)action就是一個(gè)代表該命令的字串,比如‘click’。但是一個(gè)字串是不能去執(zhí)行的啊,所以我們需要有一種方式把它轉(zhuǎn)換成可以執(zhí)行的代碼,這個(gè)就是AndroidCommandExecutor維護(hù)的一個(gè)靜態(tài)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());
    }
      這個(gè)map指定了我們支持的pc端過(guò)來(lái)的所有action,以及對(duì)應(yīng)的處理該action的類的實(shí)例,其實(shí)這些類都是CommandHandler的子類基本上就只有一個(gè):去實(shí)現(xiàn)CommandHandler的虛擬方法execute!要做的事情就大概就這幾類:
      控件相關(guān)的action:調(diào)用AndroidElement控件的成員變量UiObject el對(duì)應(yīng)的方法來(lái)執(zhí)行真實(shí)的操作
      UiDevice相關(guān)的action:調(diào)用UiDevice提供的方法
      UiScrollable相關(guān)的action:調(diào)用UiScrollable提供的方法
      UiAutomator那5個(gè)對(duì)象都沒(méi)有的action:該調(diào)用InteractionController的就反射調(diào)用,該調(diào)用QueryController的就反射調(diào)用。注意這兩個(gè)類UiAutomator是沒(méi)有提供直接調(diào)用的方法的,所以只能通過(guò)反射。更多這兩個(gè)類的信息請(qǐng)翻看之前的UiAutomator源碼分析相關(guān)的文章
      其他:如取得compressedLayoutHierarchy
      指導(dǎo)action向CommandHandler真正發(fā)生轉(zhuǎn)換的地方是在這個(gè)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給解析出來(lái)
      然后通過(guò)剛提到的map把這個(gè)action對(duì)應(yīng)的CommandHandler的實(shí)現(xiàn)類給實(shí)例化
      然后調(diào)用這個(gè)命令處理類的execute方法開(kāi)始執(zhí)行命令
      3. 命令處理示例
      我們這里就示例性的看下getText這個(gè)action對(duì)應(yīng)的CommandHandler是怎么去通過(guò)AndroidElement控件進(jìn)行設(shè)置文本的處理的:
    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.");
    }
    }
    }
      關(guān)鍵代碼就是里面通過(guò)AndroidCommand的getElement方法:
      解析傳進(jìn)來(lái)的AndroidCommand實(shí)例保存的pc端過(guò)來(lái)的json字串,找到’params‘項(xiàng)的子項(xiàng)’elementId'
      通過(guò)這個(gè)獲得的id去控件哈希表(請(qǐng)查看《Appium Android Bootstrap源碼分析之控件AndroidElement》)中找到目標(biāo)AndroidElement控件對(duì)象
      然后調(diào)用獲得的AndroidElement控件對(duì)象的getText方法:
      最終通過(guò)調(diào)用AndroidElement控件成員UiObject控件對(duì)象的getText方法取得控件文本信息
      4. 小結(jié)
      bootstrap接收到appium從pc端發(fā)送過(guò)來(lái)的json格式的鍵值對(duì)字串有多個(gè)項(xiàng):
      cmd: 這是一個(gè)action還是一個(gè)shutdown
      action:如果是一個(gè)action的話,那么是什么action,比如click
      params:擁有其他的一些子項(xiàng),比如指定操作控件在AndroidElementHash維護(hù)的控件哈希表的控件鍵值的'elementId'
      在收到這個(gè)json格式命令字串后:
      AndroidCommandExecutor會(huì)調(diào)用AndroidCommand去解析出對(duì)應(yīng)的action
      然后把a(bǔ)ction去map到對(duì)應(yīng)的真實(shí)命令處理方法CommandHandler的實(shí)現(xiàn)子類對(duì)象中
      然后調(diào)用對(duì)應(yīng)的對(duì)象的execute方法來(lái)執(zhí)行命令
    相關(guān)文章:
    Appium Android Bootstrap源碼分析之簡(jiǎn)介
    Appium Android Bootstrap之控件AndroidElement

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

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

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲AV日韩综合一区| 国产亚洲精AA在线观看SEE| 九九九精品成人免费视频| 67194熟妇在线永久免费观看| 毛片无码免费无码播放| 亚洲视频在线免费观看| 免费国产黄网站在线观看可以下载| 国产中文字幕在线免费观看| 日韩a级无码免费视频| 一级毛片在线免费看| 在线观看www日本免费网站| 希望影院高清免费观看视频| 成人A级毛片免费观看AV网站| 在线jyzzjyzz免费视频| 亚洲欧洲日产国码二区首页| 亚洲国产91精品无码专区| 午夜亚洲国产精品福利| 激情吃奶吻胸免费视频xxxx| a级毛片免费观看网站| 久久99免费视频| xxxxwww免费| 在线观看免费国产视频| 亚洲欧洲国产成人综合在线观看 | 国产亚洲精aa在线看| 亚洲中文字幕久久精品无码A | 亚洲精品成人无码中文毛片不卡| 亚洲国产精品高清久久久| 亚洲黄色在线视频| 亚洲欧美不卡高清在线| 日韩在线视频线视频免费网站| 中文字幕在线视频免费| 蜜臀98精品国产免费观看| 免费羞羞视频网站| 亚洲美女又黄又爽在线观看| 亚洲日本国产乱码va在线观看| 亚洲精品无码专区久久| 91在线免费观看| 最新欧洲大片免费在线| 亚洲国产精品专区在线观看| 亚洲精品福利视频| 久久精品国产亚洲AV天海翼|