Bootstrap是一个jar包,在启动appium脚本的时候回被push到android 的/data/Local/Tmp目录下,再通过PC端命令执行该Case
//UiAutomatorTestCase 是Android自带的测试用例集
public class Bootstrap extends UiAutomatorTestCase {
public void testRunServer() {
...
SocketServer server;
try {
//构造方法中创建一个Socket连接监听4724端口
server = new SocketServer(4724);
server.listenForever(disableAndroidWatchers, acceptSSLCerts);
} catch (final SocketServerException e) {
Logger.error(e.getError());
System.exit(1);
}
}
}
public SocketServer(final int port) throws SocketServerException {
keepListening = true;
//初始化Android命令集执行器,其中有一个map存放了appium所有能够使用的操作命令
executor = new AndroidCommandExecutor();
try {
server = new ServerSocket(port);
Logger.debug("Socket opened on port " + port);
} catch (final IOException e) {
throw new SocketServerException(
"Could not start socket server listening on " + port);
}
}
当pc端发送指令执行该测试用例时会先创建个Socket服务端连接,并调用listenForever()方法,监听4724端口,该端口与appium通信。。
public void listenForever(boolean disableAndroidWatchers, boolean acceptSSLCerts) throws SocketServerException {
//读取push过来的json文件并转成JsonObject
UpdateStrings.loadStringsJson();
if (disableAndroidWatchers) {
Logger.debug("Skipped registering crash watchers.");
} else {
//设置ANR跟Crash监听器
dismissCrashAlerts();
//设置Dialog监听器,并保持心跳检查
final TimerTask updateWatchers = new TimerTask() {
@Override
public void run() {
try {
watchers.check();
} catch (final Exception e) {
}
}
};
timer.scheduleAtFixedRate(updateWatchers, 100, 100);
}
...
try {
//等待客户端接入
client = server.accept();
in = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(), "UTF-8"));
while (keepListening) {
//处理客户端数据
handleClientData();
}
in.close();
out.close();
client.close();
Logger.debug("Closed client connection");
} catch (final IOException e) {
throw new SocketServerException("Error when client was trying to connect");
}
}
当appium客户端数据发送过来的时候回转移到handleClientData()方法
private void handleClientData() throws SocketServerException {
try {
//清空StringBuffer
input.setLength(0); // clear
String res;
int a;
// (char) -1 is not equal to -1.
// ready is checked to ensure the read call doesn't block.
while ((a = in.read()) != -1 && in.ready()) {
input.append((char) a);
}
String inputString = input.toString();
try {
//将客户端数据封装成命令
AndroidCommand cmd = getCommand(inputString);
//执行命令
res = runCommand(cmd);
} catch (final CommandTypeException e) {
//封装执行结果
res = new AndroidCommandResult(WDStatus.UNKNOWN_ERROR, e.getMessage())
.toString();
} catch (final JSONException e) {
res = new AndroidCommandResult(WDStatus.UNKNOWN_ERROR,
"Error running and parsing command").toString();
}
out.write(res);
out.flush();
} catch (final IOException e) {
throw new SocketServerException("Error processing data to/from socket ("
+ e.toString() + ")");
}
}
当接收到客户端的数据时通过命令模式,将数据封装成AndroidCommand命令,再交给命令的响应者UiDevice 或UiObject来执行
private String runCommand(final AndroidCommand cmd) {
AndroidCommandResult res;
// 结束
if (cmd.commandType() == AndroidCommandType.SHUTDOWN) {
keepListening = false;
res = new AndroidCommandResult(WDStatus.SUCCESS, "OK, shutting down");
} else if (cmd.commandType() == AndroidCommandType.ACTION) {
try {
//执行命令
res = executor.execute(cmd);
}
.....
return res.toString();
}
public AndroidCommandResult execute(final AndroidCommand command) {
try {
//获取命令的action,判断客户端传来的动作类型是否是map中支持的动作
//如果是的则由相应的动作类执行,否则异常处理
if (map.containsKey(command.action())) {
return map.get(command.action()).execute(command);
}
.............
}
封装好命令后就开始调用runCommand()执行命令.这里有个map是静态代码块初始化的,定义了appium所有可以跟UiAutomator交互的动作例如
static {
map.put("waitForIdle", new WaitForIdle());
map.put("clear", new Clear());
}
Clear类就是clear动作的执行者。我们看一个简单的waitFordle命令执行
public class WaitForIdle extends CommandHandler {
@Override
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
//获取客户端的参数
final Hashtable<String, Object> params = command.params();
long timeout = 10;
if (params.containsKey("timeout")) {
timeout = (Integer) params.get("timeout");
}
//具体的执行者执行,并返回结果
UiDevice d = UiDevice.getInstance();
d.waitForIdle(timeout);
return getSuccessResult(true);
}
}
这样我们就分析完Appium在android执行的原理了。
总结:appium是通过自身实现一个android UiAutomator框架的case,这个case创建了一个网络通信,通过appium客户端的指令来实现UI操作,并将操作结果返回给Appium客户端
QQ图片20180129192831.jpg
网友评论