欢迎关注我的 Appium 知乎专栏:自定义 Appium 之路
当 Appium 脚本中的 uiautomationName 设置为 UiAutomator1 时,会启动 UIAutomator1 的 Driver 来测试你的 Appium 脚本,在脚本之前之前,会有很多权限框弹出,此时就需要我们的 UIAutomator1 来自动处理这样的对话框,并且要在安装 apk 之前就启动 UIAutomator1 的服务。
很不幸,appium 的代码中,是先安装 Appium Setting APK 和被测应用的,那怎么改呢?
我们找到 appium-android-driver 工程,找打 lib/driver.js,然后找到 startAndroidSession 方法,将如下代码提到这个方法的最前面:
// start UiAutomator (改动:优先启动UIAutomator1)
this.bootstrap = new helpers.bootstrap(this.adb, this.bootstrapPort, this.opts.websocket);
await this.bootstrap.start(this.opts.appPackage, this.opts.disableAndroidWatchers, this.opts.acceptSslCerts);
// handling unexpected shutdown
this.bootstrap.onUnexpectedShutdown.catch(async (err) => { // eslint-disable-line promise/prefer-await-to-callbacks
if (!this.bootstrap.ignoreUnexpectedShutdown) {
await this.startUnexpectedShutdown(err);
}
});
如下图所示:
经过测试,这样不会影响 UIAutomator1 的正常启动,不会带来负面影响。
既然都优先启动了,我们就要让 UIAutomator1 去监控手机界面了。
不幸的是,Appium 并没有给我们写类似的监听代码,我们得自己动手了,其实很简单,大体思路就是,dump 控件树,检测界面控件,检测到权限框,就点"允许"、"是"之类的,这里就需要不断的枚举了。国内手机产商众多,android 版本也多,这里就有大量的工作要做了。
幸运的是,Appium 给我们做好了监控的线程,只是空实现,基本啥都没干,代码在 SocketServer.java 的 listenForever 中:
public void listenForever(boolean disableAndroidWatchers, boolean acceptSSLCerts) throws SocketServerException {
Logger.debug("Appium Socket Server Ready");
UpdateStrings.loadStringsJson();
if (disableAndroidWatchers) {
Logger.debug("Skipped registering crash watchers.");
} else {
dismissCrashAlerts();
// 看这里,就是这个每隔100毫秒触发一次的check !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
final TimerTask updateWatchers = new TimerTask() {
@Override
public void run() {
try {
watchers.check();
} catch (final Exception e) {
e.printStackTrace();
}
}
};
timer.scheduleAtFixedRate(updateWatchers, 100, 100);
}
if (acceptSSLCerts) {
Logger.debug("Accepting SSL certificate errors.");
acceptSSLCertificates();
}
try {
client = server.accept();
Logger.debug("Client connected");
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");
}
}