自定义 Appium

本贴最后更新于 2189 天前,其中的信息可能已经水流花落

改造 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

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...