摘要
大体看了下getText以及setText方法,getText很简单,直接就是通过获取到AndroidElement中的UiObject 对象元素之后直接调用getText方法。
但是setText就不是这么简单了,因为用过UiAutomator的童鞋应该都应该知道,UiAutomator是不支持中文输入的,当然如果安装第三发的输入法就另当别论了。同样appium 的desired_capabilities中unicodeKeyboard如果为True的情况下,appium默认是会给你的手机安装一个appium的输入法,这个输入法对我们来说更多的是解决了中文输入的问题。
所以在setText上,appium肯定是会做一些不小的变化的。我们这次主要就是来分析setText它到底是如何实现的。
正文
其实我阅读代码的能力真的挺弱的,所以对于较为复杂的代码要不调试,要不就是看log,boottrap不太会调试,但是我们可以通过看appium server来分析问题,所以我们这里首先先来一段测试的代码吧
self.driver.find_element_by_id("com.seewo.easicare.demo:id/care_new_notice").click()
notice_edit_text = self.driver.find_element_by_id("com.seewo.easicare.demo:id/care_add_notice_content")
notice_edit_text.send_keys("helo.\n everyone")
简单的一个文本输入内容,我们看看appium server 的log吧
对照着log 我们看下setText的源代码吧
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
AndroidElement el = null;
if (command.isElementCommand()) {
Logger.debug("Using element passed in.");
el = command.getElement();
} else {
try {
Logger.debug("Using currently-focused element.");
AndroidElementsHash elements = AndroidElementsHash.getInstance();
el = elements.getElement(new UiSelector().focused(true), "");
} catch (ElementNotFoundException e) {
Logger.debug("Error retrieving focused element: " + e);
return getErrorResult("Unable to set text without a focused element.");
}
}
try {
final Hashtable<String, Object> params = command.params();
boolean replace = Boolean.parseBoolean(params.get("replace").toString());
String text = params.get("text").toString();
boolean pressEnter = false;
if (text.endsWith("\\n")) {
pressEnter = true;
text = text.replace("\\n", "");
Logger.debug("Will press enter after setting text");
}
boolean unicodeKeyboard = false;
if (params.get("unicodeKeyboard") != null) {
unicodeKeyboard = Boolean.parseBoolean(params.get("unicodeKeyboard").toString());
}
String currText = el.getText();
new Clear().execute(command);
if (!el.getText().isEmpty()) {
// clear could have failed, or we could have a hint in the field
// we'll assume it is the latter
Logger.debug("Text not cleared. Assuming remainder is hint text.");
currText = "";
}
if (!replace) {
text = currText + text;
}
final boolean result = el.setText(text, unicodeKeyboard);
if (!result) {
return getErrorResult("el.setText() failed!");
}
if (pressEnter) {
final UiDevice d = UiDevice.getInstance();
d.pressEnter();
}
return getSuccessResult(result);
} catch (final UiObjectNotFoundException e) {
return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,
e.getMessage());
} catch (final Exception e) { // handle NullPointerException
return getErrorResult("Unknown error");
}
}
其实到这里 很多代码应该都能看明白了。
- 首先定位元素:判断命令是否是针对于元素的,如果不是的话,再去获取当前处于焦点的元素,
- 解析命令:判断是否使用unicodeKeyBoard ,判断setText是文本替换,还是文本追加,默认情况下都是进行追加文本的。但是这里有个地方要注意。也是我一开始一直疑惑的一个地方:
- 首先通过getText获取当前元素的文字,存到currText中
- 使用new Clear().execute(command);清除当前元素的所有文字
- .再次获取当前元素文字。如果文字仍不为空,认定它是hint text并把currText置空(由于此处也有可能是clear方法出错导致没有clear成功,因此留了一个log说明假设还存在的text是hint text)
- 如果replace不是true,在text前面加入currText。
所以说并不是说replace为true的情况下就进行文本追加了,最后判断文本结尾是否有回车,如果是的话就要按下回车键。
- 最后就是调用setText()方法了,只是说appium server又对setText做了一个封装,因为我们输入的内容可能是个中文,所以这个时候就要进行一些encode的处理了。
再来可以看下testerhome的这篇文章,作者写的真心棒