title: 给 Appium 内置系统对话框自动处理 - appium-uiautomator2-driver 篇

tags: [appium]

欢迎关注我的 Appium 知乎专栏:自定义 Appium 之路

当 appium 脚本的 uiautomationName 设置为 UiAutomator2 时,就会启动 appium-uiautomator2-driver 这个 driver 来执行你的脚本测试,而它的系统对话框的处理跟 UIAutomator1 的就不一样了,更加复杂一点。

因为 UIAutomator2 是一个 apk 形式的,本身可以认为是一个应用,是需要安装的,所以在启动 UIAutomator2 之前,就会碰到系统对话框的问题,此时,我们需要借助 UIAutomator1 来做这件事。

大体流程是:

  1. 启动 UIAutomator1
  2. 用 UIAutomator1 来处理权限框
  3. 安装各种 apk,包括 UIAutomator2 的 apk
  4. 杀死 UIAutomator1 服务
  5. 启动 UIAutomator2
  6. 使用 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方法,分别添加如下代码:

  1. 启动 UIAutomator1 的代码:
// 启动UIAutomator2之前,先启动UIAutomator1服务来处理系统框
await this.startUiAutomator1Service();
  1. kill UIAutomator1 的代码:
// 在启动UIAutomator2之前,要先杀死UIAutomator1服务,否则UIAutomator2无法启动
// 因为UIAutomator只允许同时存在一个
if (this.uiAutomator) {
 this.uiAutomator.shutdown();
}

位置如下图:

image-20190411171620414

image-20190411171642533

自此,nodejs 的事情就完成了,剩下的就是要改造 appium-uiautomator2-server 的代码,让它能够像 UIAutomator1 一样监听界面,自动处理。


↙↙↙阅读原文可查看相关链接,并与作者交流