MonkeyRunnerStarter是MonkeyRunner啟動時的入口類,由于它裡面包括了main方法.它的整個啟動過程主要做了以下幾件事情:
-
解析使用者啟動MonkeyRunner時從指令行傳輸進來的參數: 由于MonkeyRunner須要依據指定的參數才幹做事情,比方輸入的一個須要執行的腳本。
假設确實不知道不論什麼參數的話它就會進入MonkeyRunner的互動模式,事實上就是Jythong的互動模式,讓使用者能夠邊寫代碼邊執行
- 啟動AndroidDebugBridge: 事實上就是啟動ADBserver,由于MonkeyRunner跟裝置通信的一個很重要的方法之中的一個就是通過向ADBserver發送指令來請求目标裝置的服務
-
啟動裝置監控線程: 事實上這個是在啟動AndroidDebugBridge的時候一并啟動的。裝置監控線程主要做的事情就是取監控裝置是否有接入進來或者移除出去,假設有新的裝置連接配接進來,或者說裝置變成ONLINE狀态(一個裝置有多個狀态:ONLINE|OFFLINE|RECOVERY|UNAUTHORIZED),那麼就須要取監控裝置裡面的每一個可調試程序,這主要是用來給DDMS等調試工具使用的。
它維護了一個最新的裝置清單
- 啟動AndroidDebugBridge:
- 啟動Monkey:
- 執行測試腳本:
本小節我們會先去看下MonkeyRunner在啟動的時候是怎樣獲得指令行參數并對其進行解析處理的。
整個過程事實上跟monkey在啟動的時候的指令行參數分析相似。往下我們先看下牽涉到的關鍵類之間的關系:
圖8-2-1 MonkeyRunnerStarter類圖
從類圖中我們看到MonkeyRunnerStarter持有了一個MonkeyRunnerOptions類型的成員變量options,這個執行個體儲存的就是解析出來的指令行參數。同一時候該類會提供一個processOptions方法來專門解析指令行參數。
我們先進入到MonkeyRunnerStart這個類的main方法:
178 public static void main(String[] args) {
179 MonkeyRunnerOptions options =
MonkeyRunnerOptions.processOptions(args);
180
181 if (options == null) {
182 return;
183 }
184
185
186 replaceAllLogFormatters(MonkeyFormatter.DEFAULT_INSTANCE,
options.getLogLevel());
187
188 MonkeyRunnerStarter runner =
new MonkeyRunnerStarter(options);
189 int error = runner.run();
190
191
192 System.exit(error);
193 }
194 }
代碼3-2-1 MonkeyRunnerStart - main
這裡主要做了三件事情:
- 179行去處理使用者啟動monkeyrunner的時候輸入的指令行參數
- 188行去初始化MonkeyRunnerStarter,裡面主要是初始化了ChimpChat。ChimpChat又去開啟AndroidDebugBridge程序和開啟DeviceMonitor裝置監控線程,我們往後小節會進行具體分析
- 189行去把monkeyrunner執行起來,包括帶腳本參數的情況和不待腳本參數直接提供jython指令行的情況
我們這一節會先去分析下monkeyrunner是怎樣對參數進行處理的,我們跳轉到MonkeyRunnerOptions這個類裡面的processOptions這種方法:
93 public static MonkeyRunnerOptions processOptions(String[] args)
94 {
95 int index = 0;
96
97 String hostname = DEFAULT_MONKEY_SERVER_ADDRESS;
98 File scriptFile = null;
99 int port = DEFAULT_MONKEY_PORT;
100 String backend = "adb";
101 Level logLevel = Level.SEVERE;
102
103 ImmutableList.Builder<File> pluginListBuilder = ImmutableList.builder();
104 ImmutableList.Builder<String> argumentBuilder = ImmutableList.builder();
105 while (index < args.length) {
106 String argument = args[(index++)];
107
108 if ("-s".equals(argument)) {
109 if (index == args.length) {
110 printUsage("Missing Server after -s");
111 return null;
112 }
113 hostname = args[(index++)];
114 }
115 else if ("-p".equals(argument))
116 {
117 if (index == args.length) {
118 printUsage("Missing Server port after -p");
119 return null;
120 }
121 port = Integer.parseInt(args[(index++)]);
122 }
123 else if ("-v".equals(argument))
124 {
125 if (index == args.length) {
126 printUsage("Missing Log Level after -v");
127 return null;
128 }
129
130 logLevel = Level.parse(args[(index++)]);
131 } else if ("-be".equals(argument))
132 {
133 if (index == args.length) {
134 printUsage("Missing backend name after -be");
135 return null;
136 }
137 backend = args[(index++)];
138 } else if ("-plugin".equals(argument))
139 {
140 if (index == args.length) {
141 printUsage("Missing plugin path after -plugin");
142 return null;
143 }
144 File plugin = new File(args[(index++)]);
145 if (!plugin.exists()) {
146 printUsage("Plugin file doesn't exist");
147 return null;
148 }
149
150 if (!plugin.canRead()) {
151 printUsage("Can't read plugin file");
152 return null;
153 }
154
155 pluginListBuilder.add(plugin);
156 } else if (!"-u".equals(argument))
157 {
158 if ((argument.startsWith("-")) && (scriptFile == null))
159 {
160
161
162 printUsage("Unrecognized argument: " + argument + ".");
163 return null;
164 }
165 if (scriptFile == null)
166 {
167
168 scriptFile = new File(argument);
169 if (!scriptFile.exists()) {
170 printUsage("Can't open specified script file");
171 return null;
172 }
173 if (!scriptFile.canRead()) {
174 printUsage("Can't open specified script file");
175 return null;
176 }
177 } else {
178 argumentBuilder.add(argument);
179 }
180 }
181 }
182
183 return new MonkeyRunnerOptions(hostname,
port,
scriptFile,
backend,
logLevel,
pluginListBuilder.build(),
argumentBuilder.build());
184 }
185 }
代碼8-2-2 MonkeyRunnerOptions - processOptions
這裡首先請看99-101行的幾個變量初始化,假設使用者在指令行中沒有指定相應的參數,那麼這些預設參數就會被使用,我們且看下這些預設值各自是什麼:
- hostname:相應‘-s'參數。預設值是'127.0.0.1',也就是本機。将會forward給目标裝置執行的monkey。是以加上以下的轉發port等同于目标機器在listen的monkey服務
- port :相應‘-p'參數。預設值是'12345',也就是monkey預設監聽端口
-
backend :相應'-be'參數,預設值是‘adb‘,事實上往後看代碼我們會發現它也僅僅是支援’adb‘而已。
這裡須要注意的是這是一個隐藏參數。指令行的help沒有顯示該參數
- logLevel :相應‘-v'參數。預設值'SEVERE',也就是說僅僅列印嚴重的log
代碼往下就是對使用者輸入的參數的解析并儲存了,這裡要注意幾個隐藏的參數:
-
-u :乍一看以為這是一個什麼特别的參數。從156-178行能夠看到這個參數處理的意義是:當使用者輸入'-u'的時候不會作不論什麼處理,但當使用者輸入的是由‘-’開始的但又不是monkeyrunner聲稱支援的那幾個參數的時候,就會依據不同的情況給使用者報錯。
是以這段代碼的意思事實上就是在使用者輸入了不支援的參數的時候依據不同的情況給使用者提示而已
- -be :backend。如前所述。僅僅支援‘adb'
- -plugin :這裡須要一個背景知識,在google官網有說明,使用者能夠通過遵循一定的規範去編寫插件來擴充monkeyrunner的功能,比方在monkeydevice裡面按下這個動作是須要通過MonkeyDevice.DOWN這個參數來傳給press這種方法的。假設你認為這樣子不好,你希望添加個pressDown這種方法。裡面預設就是用MonkeyDevice.DOWN來驅動MonkeyDevice的press方法,而使用者僅僅須要給出坐标點就能夠了,那麼你就能夠遵循google描寫叙述的規範去編寫一個這方面的插件。到時使用的時候就能夠通過python方式直接import進來使用了。本書并不會把MonkeyRunner插件進行重點介紹。
在解析出全部的參數之後,processOptions方法最後依據這些參數來初始化MonkeyRunnerOptions類。
我們進入到該構造函數看下它到底做了什麼事情:
38 private MonkeyRunnerOptions(String hostname, int port, File scriptFile, String backend, Level logLevel, Collection<File> plugins, Collection<String> arguments)
39 {
40 this.hostname = hostname;
41 this.port = port;
42 this.scriptFile = scriptFile;
43 this.backend = backend;
44 this.logLevel = logLevel;
45 this.plugins = plugins;
46 this.arguments = arguments;
47 }
代碼8-2-3 MonkeyRunnerOptions - 構造函數
所做的事情很easy。就是把解析出來的全部參數儲存到MonkeyRunnerOptions類的執行個體裡面。今後須要的時候就進去拿就好了。
注:很多其它文章請關注公衆号:techgogogo或個人部落格http://techgogogo.com。當然。也很歡迎您直接微信(zhubaitian1)勾搭。