您好,登錄后才能下訂單哦!
通過上一篇文章《Appium Android Bootstrap源碼分析之控件AndroidElement》我們知道了Appium從pc端發(fā)送過來的命令如果是控件相關(guān)的話,最終目標(biāo)控件在bootstrap中是以AndroidElement對象的方式呈現(xiàn)出來的,并且該控件對象會在AndroidElementHash維護(hù)的控件哈希表中保存起來。但是appium觸發(fā)一個命令除了需要提供是否與控件相關(guān)這個信息外,還需要其他的一些信息,比如,這個是什么命令?這個就是我們這篇文章需要討論的話題了。
下面我們還是先看一下從pc端發(fā)過來的json的格式是怎么樣的:
可以看到里面除了params指定的是哪一個控件之外,還指定了另外兩個信息:
開始前我們先簡要描述下我們需要涉及到幾個關(guān)鍵類:
Class | Key Method | Key Member | Parent | Description | Comment |
AndroidComma ndType | | enum AndroidCommandType { ACTION,SHUTDOWN } | | 安卓命令的類型,只有兩種,shutdown的處理方式和普通的action會不一樣 | |
AndroidComma nd | action/getElement | JSONObject json; AndroidCommandType cmdType; | | 從用戶發(fā)過來的json命令信息得到真正的命令 | |
CommandHand ler | execute | | | 虛擬類,其他真實CommandHandler如click的父類 | |
AndroidComma ndExecutor | execute | HashMap< String, CommandHan dler> map | | map是所有的命令字串和真實的CommandHandler的一個映射。 其成員函數(shù)execute就是通過字串命令找到map對應(yīng)的handler然后執(zhí)行的 | |
getText | execute | | CommandHandler | 處理獲取指定控件文本信息的類。 真正執(zhí)行的是傳進(jìn)來的AndroidCommand對應(yīng)UiObject的getText方法 | 其他click,find,drag,setText等命令同理 |
JSONObject json; AndroidCommandType cmdType;json就是pc過來的json格式的那串命令,cmdType就是action或者shutdown,其實就是用來把這個類偽裝成更像個命令類而已,我認(rèn)為如果不提供這個成員變量而直接修改其getType的實現(xiàn)去解析json字串直接獲得對應(yīng)的AndroidCommandType,然后把這個類的名字改成AndroidCommandParser得了。
那么我們往下看下AndroidCommand究竟是怎么對客戶端命令進(jìn)行解析的,它的方法都很短,所以我把它做成一個表,這樣比較清晰點(diǎn):
Method | Return | Code | Description |
AndroidCommand | N/A |
public AndroidCommand(final String jsonStr) throws JSONException, CommandTypeException { json = new JSONObject(jsonStr); setType(json.getString("cmd")); } | 構(gòu)造函數(shù)構(gòu)造函數(shù),把客戶端過 來的json格式命 令保存起來并根 據(jù)命令的cmd項 設(shè)置好cmdType |
action() | String |
public String action() throws JSONException { if (isElementCommand()) { return json.getString("action"). substring(8); } return json.getString("action"); } | 解析出客戶端過 來的json字串的 action這個項并 返回 |
commandType() | AndroidCom mandType |
public AndroidCommandType commandType() { return cmdType; } | 是ACTION還是SHUTDOWN |
getDestElement | AndroidElement |
public AndroidElement getDestElement() throws JSONException { String destElId = (String) params(). get("destElId"); return AndroidElementsHash. getInstance(). getElement(destElId); } | 解析出json字串 中params項的子 項destElId,然后 從控件哈希表中 找到目標(biāo) AndroidElement 控件返回 |
getElement | AndroidElement |
public AndroidElement getElement() throws JSONException { String elId = (String) params(). get("elementId"); return AndroidElementsHash.getInstance(). getElement(elId); } | 解析出json字串 中params項的子 項elementId,然 后從控件哈希表 中找到目標(biāo) AndroidElement 控件返回 |
isElementCommand | boolean |
public boolean isElementCommand() { if (cmdType == AndroidCommandType.ACTION) { try { return json.getString("action"). startsWith("element:"); } catch (final JSONException e) { return false; } } return false; } | 解析json字串中 的’action’項的值,如果是以’element:’ 字串開始的話就證 明是個控件相關(guān)的 命令,否則就不是
|
params | Hashtable <String, Object> |
public Hashtable<String, Object> params() throws JSONException { final JSONObject paramsObj = json.getJSONObject("params"); final Hashtable<String, Object> newParams = new Hashtable<String, Object>(); final Iterator<?> keys = paramsObj.keys(); while (keys.hasNext()) { final String param = (String) keys.next(); newParams.put(param, paramsObj.get(param)); } return newParams; } | json字串中的params項解析器 |
setType | void |
public void setType(final String stringType) throws CommandTypeException { if (stringType.equals("shutdown")) { cmdType = AndroidCommandType.SHUTDOWN; } else if (stringType.equals("action")) { cmdType = AndroidCommandType.ACTION; } else { throw new CommandTypeException( "Got bad command type: " + stringType); } } | 就是構(gòu)造函數(shù)根 據(jù)json字串的 ’cmd’這個項的值 來調(diào)用這個方法 來設(shè)置的AndroidCommand Type |
從表中的這些方法可以看出來,這個類所做的事情基本上都是怎么去解析appium從pc端過來的那串json字串。
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,以及對應(yīng)的處理該action的類的實例,其實這些類都是CommandHandler的子類基本上就只有一個:去實現(xiàn)CommandHandler的虛擬方法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!"); } }
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 getSucce***esult(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)鍵代碼就是里面通過AndroidCommand的getElement方法:
作者 | 自主博客 | 微信 | CSDN |
天地會珠海分舵 | http://techgogogo.com | 服務(wù)號:TechGoGoGo 掃描碼:
| 向AI問一下細(xì)節(jié) 免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。 猜你喜歡最新資訊相關(guān)推薦相關(guān)標(biāo)簽AI
助 手 |