通过上一篇文章《Appium Android Bootstrap源码分析之控件AndroidElement》我们知道了Appium从pc端发送过来的命令如果是控件相关的话,最终目标控件在bootstrap中是以AndroidElement对象的方式呈现出来的,并且该控件对象会在AndroidElementHash维护的控件哈希表中保存起来。但是appium触发一个命令除了需要提供是否与控件相关这个信息外,还需要其他的一些信息,比如,这个是什么命令?这个就是我们这篇文章需要讨论的话题了。
下面我们还是先看一下从pc端发过来的json的格式是怎么样的:
可以看到里面除了params指定的是哪一个控件之外,还指定了另外两个信息:
- cmd: 这是一个action还是一个shutdown
- action:如果是一个action的话,那么是什么action
开始前我们先简要描述下我们需要涉及到几个关键类:
| Class | Key Method | Key Member | Parent | Description | Comment |
| AndroidComma ndType | | enum AndroidCommandType { ACTION,SHUTDOWN } | | 安卓命令的类型,只有两种,shutdown的处理方式和普通的action会不一样 | |
| AndroidComma nd | action/getElement | JSONObject json; AndroidCommandType cmdType; | | 从用户发过来的json命令信息得到真正的命令 | |
| CommandHand ler | execute | | | 虚拟类,其他真实CommandHandler如click的父类 | |
| AndroidComma ndExecutor | execute | HashMap< String, CommandHan dler> map | | map是所有的命令字串和真实的CommandHandler的一个映射。 其成员函数execute就是通过字串命令找到map对应的handler然后执行的 | |
| getText | execute | | CommandHandler | 处理获取指定控件文本信息的类。 真正执行的是传进来的AndroidCommand对应UiObject的getText方法 | 其他click,find,drag,setText等命令同理 |
1. Appium命令解析器AndroidCommand
- JSONObject json;
- AndroidCommandType cmdType;
那么我们往下看下AndroidCommand究竟是怎么对客户端命令进行解析的,它的方法都很短,所以我把它做成一个表,这样比较清晰点:
| Method | Return | Code | Description |
| AndroidCommand | N/A |
| 构造函数构造函数,把客户端过 来的json格式命 令保存起来并根 据命令的cmd项 设置好cmdType |
| action() | String |
| 解析出客户端过 来的json字串的 action这个项并 返回 |
| commandType() | AndroidCom mandType |
| 是ACTION还是SHUTDOWN |
| getDestElement | AndroidElement |
| 解析出json字串 中params项的子 项destElId,然后 从控件哈希表中 找到目标 AndroidElement 控件返回 |
| getElement | AndroidElement |
| 解析出json字串 中params项的子 项elementId,然 后从控件哈希表 中找到目标 AndroidElement 控件返回 |
| isElementCommand | boolean |
| 解析json字串中 的’action’项的值,如果是以’element:’ 字串开始的话就证 明是个控件相关的 命令,否则就不是
|
| params | Hashtable <String, Object> |
| json字串中的params项解析器 |
| setType | void |
| 就是构造函数根 据json字串的 ’cmd’这个项的值 来调用这个方法 来设置的AndroidCommand Type |
从表中的这些方法可以看出来,这个类所做的事情基本上都是怎么去解析appium从pc端过来的那串json字串。
2. Action与CommandHandler的映射关系
- 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());
- }
- 控件相关的action:调用AndroidElement控件的成员变量UiObject el对应的方法来执行真实的操作
- UiDevice相关的action:调用UiDevice提供的方法
- UiScrollable相关的action:调用UiScrollable提供的方法
- UiAutomator那5个对象都没有的action:该调用InteractionController的就反射调用,该调用QueryController的就反射调用。注意这两个类UiAutomator是没有提供直接调用的方法的,所以只能通过反射。更多这两个类的信息请翻看之前的UiAutomator源码分析相关的文章
- 其他:如取得compressedLayoutHierarchy
- 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实例保存的pc端过来的json字串,找到’params‘项的子项’elementId'
- 通过这个获得的id去控件哈希表(请查看《Appium Android Bootstrap源码分析之控件AndroidElement》)中找到目标AndroidElement控件对象
- 最终通过调用AndroidElement控件成员UiObject控件对象的getText方法取得控件文本信息
4. 小结
- cmd: 这是一个action还是一个shutdown
- action:如果是一个action的话,那么是什么action,比如click
- params:拥有其他的一些子项,比如指定操作控件在AndroidElementHash维护的控件哈希表的控件键值的'elementId'
- AndroidCommandExecutor会调用AndroidCommand去解析出对应的action
- 然后把action去map到对应的真实命令处理方法CommandHandler的实现子类对象中
- 然后调用对应的对象的execute方法来执行命令
| Item | Description | Warning |
| Author | 天地会珠海分舵 | 转载请注明出处! 更多精彩文章请查看本人博客! |
| Blog Address |
本文深入探讨了Appium中如何解析客户端发送的json命令,特别关注了命令类型(action或shutdown)、参数解析及如何将命令映射到实际的Action执行。通过解析JSON命令,Appium能够识别具体的Action并调用相应的CommandHandler类执行,从而实现对Android应用的自动化控制。
4903

被折叠的 条评论
为什么被折叠?



