Android(安卓)Appium源码分析
16lz
2021-12-04
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 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
更多相关文章
- Android模拟器无法上网解决方案
- 2011.09.23——— android sample之Notepad(context menu)
- android listview onItemClick不执行
- Android(安卓)SDK中的必会工具-android
- Ubuntu下编译AOSP步骤
- Android中bindService的使用及Service生命周期
- 用CSS3生成的一个漂亮的android客户端页面
- Android命令行启动程序-am命令的使用-纠正网上大部分资料的错误
- Android客户端向服务器端发送数据的流程(1)