V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cmlanche
V2EX  ›  程序员

自定义 appium

  •  
  •   cmlanche ·
    cmlanche · 2019-04-02 18:44:20 +08:00 · 999 次点击
    这是一个创建于 1821 天前的主题,其中的信息可能已经有所发展或是发生改变。

    改造 appium-android-driver

    这个 driver 是 UIAutomator1 的 driver,负责 UIAutomator1 的服务启动、停止、命令接收和执行。

    工程结构

    • appium-android-driver(NodeJS 工程)
      • bootstrap(Maven 工程)

    本身 appium-android-driver 是一个 nodejs 工程,它还套着一个 bootstrap 的 maven 工程,这个 maven 工程就是用来打包 UIAutomator1 的,会再 bootstrap/bin 的目录下构建生成一个叫 AppiumBootstrap.jar 的供外层的 NodeJS 工程使用。代码在appium-android-driver/lib/bootstrap.js的 start 函数中

          const rootDir = path.resolve(__dirname, '..', '..');
          const startDetector = (s) => { return /Appium Socket Server Ready/.test(s); };
          const bootstrapJar = path.resolve(rootDir, 'bootstrap', 'bin', 'AppiumBootstrap.jar');
    
          await this.init();
          await this.adb.forwardPort(this.systemPort, 4724);
          this.process = await this.uiAutomator.start(
                           bootstrapJar, 'io.appium.android.bootstrap.Bootstrap',
                           startDetector, '-e', 'pkg', appPackage,
                           '-e', 'disableAndroidWatchers', disableAndroidWatchers,
                           '-e', 'acceptSslCerts', acceptSslCerts);
    

    修改 pom.xml ,编译 bootstrap,输出 AppiumBootstrap.jar

    bootstrap 工程是一个 maven 工程,用 idea 直接 open 这个文件夹即可,找到 pom.xml ,右键 Maven->Reimport,我们会发现有两个 maven 依赖无法导入,报找不到对应的 jar 包:

    <dependency>
      <groupId>android</groupId>
      <artifactId>android</artifactId>
      <version>4.4.2_r4</version>
    </dependency>
    
    <dependency>
      <groupId>android.test.uiautomator</groupId>
      <artifactId>uiautomator</artifactId>
      <version>4.4.2_r4</version>
    </dependency>
    

    原因是默认的仓库是从https://repo.maven.appache.org/maven2中找的,而这个仓库根本没有这两个库。

    后来我发现 Boundless 的仓库http://repo.boundlessgeo.com/main/中是有的,在这个 pom.xml 中配置这个仓库就可以下载了。

    <project>
    ...
        <repositories>
            <repository>
                <id>Boundless</id>
                <url>http://repo.boundlessgeo.com/main/</url>
            </repository>
        </repositories>
    </project>
    

    依赖库搞定后,cmd 切换到 bootstrap 文件夹目录下,执行mvn clean package构建 maven 工程,我们会发现,并没有在 bin 目录下生成 AndroidBootstrap.jar ,此时要修改 pom.xml 中的maven-jar-plugin

    <plugin>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <!--jar 输出目录-->
        <outputDirectory>./bin</outputDirectory>
        <!--输出的 jar 包名称-->
        <finalName>AppiumBootstrap</finalName>
      </configuration>
    </plugin>
    

    重新执行mvn clean package,AppiumBootstrap.jar 就完成了正常构建,也就是说 UIAutomator1 构建好了。

    自定义 appium-android-driver,并发布

    找到 appium-android-driver/package.json,修改 name,比如修改为appium-android-driver2,然后顺便修改下 version,然后再 appium-android-driver 根目录下执行

    npm install  # 重新安装依赖
    npm publish  # 发布
    

    npm publish是发布 nodejs 包的命令,需要你在[npmjs.com](https://www.npmjs.com)上注册自己的账号,发布的时候需要验证你的账号。

    自定义 Appium

    跟自定义 appium-android-driver 一样,我们找到 package.json,修改 name 和 version,比如分别是 appium2 和 1.12.1-20190401a,顺便我们修改一下 lib/main.js 中的一条语句,以验证我们的修改是否生效:

    async function logStartupInfo (parser, args) {
      let welcome = `Welcome to Appium2 v${APPIUM_VER}, modified by chengming`; // 我修改了此处
      let appiumRev = await getGitRev();
      if (appiumRev) {
        welcome += ` (REV ${appiumRev})`;
      }
      logger.info(welcome);
    
      let showArgs = getNonDefaultArgs(parser, args);
      if (_.size(showArgs)) {
        logNonDefaultArgsWarning(showArgs);
      }
      let deprecatedArgs = getDeprecatedArgs(parser, args);
      if (_.size(deprecatedArgs)) {
        logDeprecationWarning(deprecatedArgs);
      }
      if (!_.isEmpty(args.defaultCapabilities)) {
        logDefaultCapabilitiesWarning(args.defaultCapabilities);
      }
      // TODO: bring back loglevel reporting below once logger is flushed out
      // logger.info('Console LogLevel: ' + logger.transports.console.level);
      // if (logger.transports.file) {
      //   logger.info('File LogLevel: ' + logger.transports.file.level);
      // }
    }
    

    还有要在package.json中,找到 dependencies,把我们的 appium 的 UIAutomator1 的依赖改为**"appium-android-driver2":"latest"**,使我们自定义的 appium 能够使用我们自定义的UIAutomator1 driver

    同样,重新构建和发布:

    npm install
    npm publish
    

    npmjs.com 网站中,我的项目下就会看到 appium2 的工程:

    image-20190402112045705

    使用自定义的 appium

    安装:

    npm i -g appium2
    

    启动

    appium
    

    效果

    image-20190402112501248

    TODO:验证自定义 appium-android-driver 是否生效

    这个要修改 bootstrap 的 java 代码,在启动 server 的时候加上你的日志即可验证,后续再补充吧。

    补充:2019-04-02 17:20

    纠正 AppiumBootstrap.jar 的打包方式

    官方readme.md没有说怎么打包这个 jar 包的事情,我按照如上述的打包方式生成的 jar 是不可用的,格式不正确。jar 中的内容应该是一个 classes.dex 文件,而不是编译好的 classes。

    image-20190402152727758

    我们需要先把 class 文件打包成 dex,然后再把 dex 打包成 jar,shell 代码如下:

    dx --dex --output=./classes.dex target/classes
    jar -cvf AppiumBootstrap.jar -C ./ ./classes.dex
    

    你需要配置好 android 的环境变量,使你的 dx 能够全局调用。

    既然打包方式知道了,并且 appium 是要求在 appium-android-driver/bootstrap/bin 下有个 AppiumBootstrap.jar 的,那么我们去掉此前给 maven-jar-plugin 设置的 configuration,重新编写一个 shell 脚本bootstrap.sh

    #!/bin/sh
    mvn clean package # 清理环境,编译 class 文件
    dx --dex --output=./target/classes.dex target/classes # 将 class 文件打包,生成 dex 文件
    jar -cvf bin/AppiumBootstrap.jar -C ./ ./target/classes.dex # 将 dex 文件打包,生成 jar
    

    测试 AppiumBootstrap.jar

    我们找到 bootstrap 工程中的io.appium.android.bootstrap.Bootstrap.java,在 testRunServer 方法的第一句,添加一段注释:

    public class Bootstrap extends UiAutomatorTestCase {
    
      public void testRunServer() {
        Logger.info("这是我自定义的 Bootstrap,成功啦...");
        Find.params = getParams();
        boolean disableAndroidWatchers = Boolean.parseBoolean(getParams().getString("disableAndroidWatchers"));
        boolean acceptSSLCerts = Boolean.parseBoolean(getParams().getString("acceptSslCerts"));
    
        SocketServer server;
        try {
          server = new SocketServer(4724);
          server.listenForever(disableAndroidWatchers, acceptSSLCerts);
        } catch (final SocketServerException e) {
          Logger.error(e.getError());
          System.exit(1);
        }
    
      }
    }
    

    电脑插上手机,执行:

    adb devices
    

    输出:

    chengmingdeMacBook-Pro:bootstrap cmlanche$ adb devices
    List of devices attached
    cf02d869	device
    

    确保你的手机是连上电脑的。

    保存,执行 bootstrap.sh ,在 bin 目录会打包好 AppiumBootstrap.jar ,我们把它 push 到手机:

    adb push ./bin/AppiumBootstrap.jar /data/local/tmp/AppiumBootstrap.jar
    

    完成后,我们启动 UIAutomator1 的测试:

    adb shell uiautomator runtest /data/local/tmp/AppiumBootstrap.jar -c io.appium.android.bootstrap.Bootstrap
    

    image-20190402171841536

    自定义 AppiumBootstrap 至此流程已通,接下来就是自定义权限框处理,让 Appium 自主识别权限框。

    —— by cmlanche.com

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5393 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 09:12 · PVG 17:12 · LAX 02:12 · JFK 05:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.