原文地址:http://www.it165.net/pro/html/201407/17696.html
成都创新互联于2013年创立,是专业互联网技术服务公司,拥有项目成都做网站、成都网站制作、成都外贸网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元万源做网站,已为上家服务,为万源各地企业和个人服务,联系电话:18980820575
bootstrap结构
如图所示为bootstrap的项目结构
 
  
01.package io.appium.android.bootstrap;02. 03.import io.appium.android.bootstrap.exceptions.SocketServerException;04. 05.import com.android.uiautomator.testrunner.UiAutomatorTestCase;06. 07./**08.*   The Bootstrap class runs the socket server. uiautomator开发的脚本,可以直接在pc端启动09.*/10.public class Bootstrap extends UiAutomatorTestCase   {11. 12.public void testRunServer()   {13.SocketServer   server;14.try {15.//   启动socket服务器,监听4724端口。16.server   = new SocketServer(4724);17.server.listenForever();18.} catch (final SocketServerException   e) {19.Logger.error(e.getError());20.System.exit(1);21.}22. 23.}24.}该类继承自UiAutomatorTestCase。所以它才能通过adb shell uiautomator runtest AppiumBootstrap.jar -c io.appium.android.bootstrap.Bootstrap被执行。
该类很简单,就是启动线程,监听4724端口,该端口与appium通信。
然后走server.listenForever()方法。
SocketServer.java
01./**02.*   Listens on the socket for data, and calls {@link #handleClientData()} when03.*   it's available.04.*05.*   @throws SocketServerException06.*/07.public void listenForever() throws SocketServerException   {08.Logger.debug("Appium   Socket Server Ready");09.//读取strings.json文件的数据10.UpdateStrings.loadStringsJson();11.//   注册两种监听器:AND和Crash12.dismissCrashAlerts();13.final TimerTask   updateWatchers = new TimerTask()   {14.@Override15.public void run()   {16.try {17.//   检查系统是否有异常18.watchers.check();19.} catch (final Exception   e) {20.}21.}22.};23.//   计时器,0.1秒后开始,每隔0.1秒执行一次。24.timer.scheduleAtFixedRate(updateWatchers, 100, 100);25. 26.try {27.client   = server.accept();28.Logger.debug("Client   connected");29.in   = new BufferedReader(new InputStreamReader(client.getInputStream(),30."UTF-8"));31.out   = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),32."UTF-8"));33.while (keepListening)   {34.//   获取客户端数据35.handleClientData();36.}37.in.close();38.out.close();39.client.close();40.Logger.debug("Closed   client connection");41.} catch (final IOException   e) {42.throw new SocketServerException("Error   when client was trying to connect");43.}44.}该方法中首先调用UpdateStrings.loadStringsJson();该方法如下:
UpdateStrings
01./**02.*   strings.json文件保存的是apk的strings.xml里的内容,在Bootstrap启动前由appium服务器解析并push到设备端的03.*04.*   @return05.*/06.public static boolean loadStringsJson()   {07.Logger.debug("Loading   json...");08.try {09.final String   filePath = "/data/local/tmp/strings.json";10.final File   jsonFile = new File(filePath);11.//   json will not exist for apks that are only on device12.//   你的case必须写明apk的路径,如果启动设备上已有的应用而case中没有app路径,此时json文件是不存在的13.//   because the node server can't extract the json from the apk.14.if (!jsonFile.exists())   {15.return false;16.}17.final DataInputStream   dataInput = new DataInputStream(18.new FileInputStream(jsonFile));19.final byte[]   jsonBytes = new byte[(int)   jsonFile.length()];20.dataInput.readFully(jsonBytes);21.//   this closes FileInputStream22.dataInput.close();23.final String   jsonString = new String(jsonBytes, "UTF-8");24.//   将读取出来的信息赋给Find类中的属性,以做后用25.Find.apkStrings   = new JSONObject(jsonString);26.Logger.debug("json   loading complete.");27.} catch (final Exception   e) {28.Logger.error("Error   loading json: " +   e.getMessage());29.return false;30.}31.return true;32.}然后回到ServerSocket类的listenForever(),此时执行到dismissCrashAlerts();该方法作用是注册一些监听器,观察是否有糖出口或者AND和crash的异常。
1.public void dismissCrashAlerts()   {2.try {3.new UiWatchers().registerAnrAndCrashWatchers();4.Logger.debug("Registered   crash watchers.");5.} catch (final Exception   e) {6.Logger.debug("Unable   to register crash watchers.");7.}8.}此时listenForever()方法里执行到注册心跳程序,每隔0.1秒开始执行一遍上面注册的监听器来检查系统是否存在异常。
01.final TimerTask   updateWatchers = new TimerTask()   {02.@Override03.public void run()   {04.try {05.//   检查系统是否有异常06.watchers.check();07.} catch (final Exception   e) {08.}09.}10.};11.//   计时器,0.1秒后开始,每隔0.1秒执行一次。12.timer.scheduleAtFixedRate(updateWatchers, 100, 100);然后启动数据通道,接受客户端发来的数据和返回结果给客户端。
1.client   = server.accept();2.Logger.debug("Client   connected");3.in   = new BufferedReader(new InputStreamReader(client.getInputStream(),4."UTF-8"));5.out   = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),6."UTF-8"));接下来就是最重要的方法handleClientData();到此listenForever()方法的主要作用就完成了。现在来看handleClientData()方法做了啥。
01./**02.*   When data is available on the socket, this method is called to run the03.*   command or throw an error if it can't.04.*05.*   @throws SocketServerException06.*/07.private void handleClientData() throws SocketServerException   {08.try {09.input.setLength(0); //   clear10. 11.String   res;12.int a;13.//   (char) -1 is not equal to -1.14.//   ready is checked to ensure the read call doesn't block.15.while ((a   = in.read()) != -1 &&   in.ready()) {16.input.append((char)   a);17.}18.final String   inputString = input.toString();19.Logger.debug("Got   data from client: " +   inputString);20.try {21.final "http://www.it165.net/pro/ydad/" target="_blank" class="keylink">AndroidCommand   cmd = getCommand(inputString);22.Logger.debug("Got   command of type " +   cmd.commandType().toString());23.res   = runCommand(cmd);24.Logger.debug("Returning   result: " + res);25.} catch (final CommandTypeException   e) {26.res   = new "http://www.it165.net/pro/ydad/" target="_blank"class="keylink">AndroidCommandResult(WDStatus.UNKNOWN_ERROR,   e.getMessage())27..toString();28.} catch (final JSONException   e) {29.res   = new AndroidCommandResult(WDStatus.UNKNOWN_ERROR,30."Error   running and parsing command").toString();31.}32.out.write(res);33.out.flush();34.} catch (final IOException   e) {35.throw new SocketServerException("Error   processing data to/from socket ("36.+   e.toString() + ")");37.}38.}该方法中读取客户端发来的数据,利用getCommand()方法获得AndroidCommand对象,然后执行runCommand()方法,获取直接的结果。那么该方法的作用就转移到了runCommand()。所以现在就来看runCommand()方法是啥意思啦。
01./**02.*   When {@link #handleClientData()} has valid data, this method delegates the03.*   command.04.*05.*   @param cmd06.*            AndroidCommand07.*   @return Result08.*/09.private String   runCommand(final AndroidCommand   cmd) {10.AndroidCommandResult   res;11.if (cmd.commandType()   == AndroidCommandType.SHUTDOWN) {12.keepListening   = false;13.res   = new AndroidCommandResult(WDStatus.SUCCESS, "OK,   shutting down");14.} else if (cmd.commandType()   == AndroidCommandType.ACTION) {15.try {16.res   = executor.execute(cmd);17.} catch (final Exception   e) {18.res   = new AndroidCommandResult(WDStatus.UNKNOWN_ERROR,   e.getMessage());19.}20.} else {21.//   this code should never be executed, here for future-proofing22.res   = new AndroidCommandResult(WDStatus.UNKNOWN_ERROR,23."Unknown   command type, could not execute!");24.}25.return res.toString();26.}27.}该方法首先做了判断,判断命令数据哪种类型,主要有关机命令和动作命令,我们主要关注动作命令,因为动作有很多种。所以来关注第一个else if中的AndroidCommandExecutor.execute()方法。主线又转移到了该方法中了,切去瞅一眼。
AndroidCommandExecutor.java
01./**02.*   Gets the handler out of the map, and executes the command.03.*04.*   @param command05.*            The {@link AndroidCommand}06.*   @return {@link AndroidCommandResult}07.*/08.public AndroidCommandResult   execute(final AndroidCommand   command) {09.try {10.Logger.debug("Got   command action: " +   command.action());11. 12.if (map.containsKey(command.action()))   {13.return map.get(command.action()).execute(command);14.} else {15.return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND,16."Unknown   command: " + command.action());17.}18.} catch (final JSONException   e) {19.Logger.error("Could   not decode action/params of command");20.return new AndroidCommandResult(WDStatus.JSON_DECODER_ERROR,21."Could   not decode action/params of command, please check format!");22.}23.}该方法中终于要执行命令的实体啦
1.if (map.containsKey(command.action()))   {2.return map.get(command.action()).execute(command);3.} else {4.return new AndroidCommandResult(WDStatus.UNKNOWN_COMMAND,5."Unknown   command: " + command.action());6.}关键是上面这几行代码,调用了map.get(command.action()).execute(command).看来要想弄懂这个命令的意思,肯定得知道map里存放的对象是哪些,那么在该类中找到map的初始化代码:
01.static {02.map.put("waitForIdle", new WaitForIdle());03.map.put("clear", new Clear());04.map.put("orientation", new Orientation());05.map.put("swipe", new Swipe());06.map.put("flick", new Flick());07.map.put("drag", new Drag());08.map.put("pinch", new Pinch());09.map.put("click", new Click());10.map.put("touchLongClick", new TouchLongClick());11.map.put("touchDown", new TouchDown());12.map.put("touchUp", new TouchUp());13.map.put("touchMove", new TouchMove());14.map.put("getText", new GetText());15.map.put("setText", new SetText());16.map.put("getName", new GetName());17.map.put("getAttribute", new GetAttribute());18.map.put("getDeviceSize", new GetDeviceSize());19.map.put("scrollTo", new ScrollTo());20.map.put("find", new Find());21.map.put("getLocation", new GetLocation());22.map.put("getSize", new GetSize());23.map.put("wake", new Wake());24.map.put("pressBack", new PressBack());25.map.put("dumpWindowHierarchy", new DumpWindowHierarchy());26.map.put("pressKeyCode", new PressKeyCode());27.map.put("longPressKeyCode", new LongPressKeyCode());28.map.put("takeScreenshot", new TakeScreenshot());29.map.put("updateStrings", new UpdateStrings());30.map.put("getDataDir", new GetDataDir());31.map.put("performMultiPointerGesture", new MultiPointerGesture());32.map.put("openNotification", new OpenNotification());33.}豁然开朗,该map是
继承CommandHandler的对象有很多,我挑一个来讲讲它具体是干嘛的,其他的我以后会挨个讲,就挑click吧。
加入现在传过来的命令后缀是click的话,那么它会调用Click对象的execute方法。
Click.java
01.package io.appium.android.bootstrap.handler;
                                                名称栏目:appium框架之bootstrap                                                文章源于:http://www.cqwzjz.cn/article/gossdh.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 