<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)論排行榜

    主站蜘蛛池模板: 亚洲国产精品无码中文字| 精品免费国产一区二区三区| 亚洲国产成人精品91久久久| 亚洲一日韩欧美中文字幕在线| 噼里啪啦免费观看高清动漫4| 自怕偷自怕亚洲精品| 国产精品白浆在线观看免费| 久久久无码精品亚洲日韩蜜桃 | 亚洲中文字幕无码专区| 男女男精品网站免费观看| va亚洲va日韩不卡在线观看| 美女黄频a美女大全免费皮| 一级毛片直播亚洲| 国产99精品一区二区三区免费 | 亚洲码和欧洲码一码二码三码| 毛片A级毛片免费播放| 亚洲欧美aⅴ在线资源| 免费中文字幕不卡视频| 免费一级毛片在线播放视频免费观看永久| 国产一区二区视频免费| 一个人看的在线免费视频| 国产亚洲一区二区精品| 91大神在线免费观看| 亚洲色一区二区三区四区| 亚洲AⅤ视频一区二区三区| 精品一区二区三区免费观看 | 亚洲午夜精品第一区二区8050| 91av免费在线视频| 亚洲尹人九九大色香蕉网站| 在线观看成人免费视频不卡| 亚洲av色香蕉一区二区三区蜜桃| 亚洲精品国产精品乱码不卡| 青青青国产手机频在线免费观看| 亚洲另类视频在线观看| 人人狠狠综合久久亚洲高清| 日韩视频免费在线观看| 久久亚洲精品国产亚洲老地址| 亚洲精品在线视频| 99视频免费播放| 国产亚洲成在线播放va| 亚洲男人第一av网站|