自定義appium

改造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上註冊自己的賬號,發佈的時候需要驗證你的賬號。

自定義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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章