自定义Appium之路 给 Appium 内置系统对话框自动处理 - appium-uiautomator2-driver 篇
title: 给 Appium 内置系统对话框自动处理 - appium-uiautomator2-driver 篇
tags: [appium]
欢迎关注我的 Appium 知乎专栏:自定义 Appium 之路
当 appium 脚本的 uiautomationName 设置为 UiAutomator2 时,就会启动 appium-uiautomator2-driver 这个 driver 来执行你的脚本测试,而它的系统对话框的处理跟 UIAutomator1 的就不一样了,更加复杂一点。
因为 UIAutomator2 是一个 apk 形式的,本身可以认为是一个应用,是需要安装的,所以在启动 UIAutomator2 之前,就会碰到系统对话框的问题,此时,我们需要借助 UIAutomator1 来做这件事。
大体流程是:
- 启动 UIAutomator1
- 用 UIAutomator1 来处理权限框
- 安装各种 apk,包括 UIAutomator2 的 apk
- 杀死 UIAutomator1 服务
- 启动 UIAutomator2
- 使用 UIAutomator2 来监控界面,处理系统对话框
怎么做呢?
首先我们需要修改 appium-uiautomator2-driver,因为原本的执行流程根本没有 UIAutomator1 的事情,我们需要把 UIAutomator1 引用进来:(appium-uiautomator2-driver/lib/driver.js)
import { androidHelpers, androidCommands, SETTINGS_HELPER_PKG_ID, UiAutomator } from 'appium-android-driver-cmext';
上面代码中的 UiAutomator 是我新加的,但是在 appium-android-driver 中并没有导出 UiAutomator 的,我们需要给它导出来:(在 appium-uiautomator2-driver/index.js)
import * as driver from './lib/driver';
import * as androidHelperIndex from './lib/android-helpers';
import * as commandIndex from './lib/commands/index';
import * as webview from './lib/webview-helpers';
import * as caps from './lib/desired-caps';
import * as uia from './lib/uiautomator'; // 这是新增
const { AndroidDriver } = driver;
const { UiAutomator } = uia; // 这是新增
const { helpers: webviewHelpers, NATIVE_WIN, WEBVIEW_WIN, WEBVIEW_BASE,
CHROMIUM_WIN } = webview;
const { commonCapConstraints } = caps;
const { commands: androidCommands } = commandIndex;
const { helpers: androidHelpers, SETTINGS_HELPER_PKG_ID } = androidHelperIndex;
export default AndroidDriver;
export {
androidHelpers, androidCommands, AndroidDriver, startServer,
commonCapConstraints, webviewHelpers, NATIVE_WIN, WEBVIEW_WIN,
WEBVIEW_BASE, CHROMIUM_WIN, SETTINGS_HELPER_PKG_ID, UiAutomator // 这是新增
};
添加一个启动 UIAutomator1 服务的方法:(appium-uiautomator2-driver/lib/driver.js)
async startUiAutomator1Service () {
const rootDir = path.resolve(__dirname, '..', '..', '..', 'appium-android-driver');
const startDetector = (s) => { return /Appium Socket Server Ready/.test(s); };
const bootstrapJar = path.resolve(rootDir, 'bootstrap', 'bin', 'AppiumBootstrap.jar');
this.uiAutomator = new UiAutomator(this.adb);
await this.uiAutomator.start(
bootstrapJar, 'io.appium.android.bootstrap.Bootstrap',
startDetector);
}
因为这个 driver.js 没有导入 path,我们还要导入 path:
import path from 'path';
然后我们找到startUiAutomator2Session
方法,分别添加如下代码:
- 启动 UIAutomator1 的代码:
// 启动UIAutomator2之前,先启动UIAutomator1服务来处理系统框
await this.startUiAutomator1Service();
- kill UIAutomator1 的代码:
// 在启动UIAutomator2之前,要先杀死UIAutomator1服务,否则UIAutomator2无法启动
// 因为UIAutomator只允许同时存在一个
if (this.uiAutomator) {
this.uiAutomator.shutdown();
}
位置如下图:
自此,nodejs 的事情就完成了,剩下的就是要改造 appium-uiautomator2-server 的代码,让它能够像 UIAutomator1 一样监听界面,自动处理。