【编者按】Nicolas Frankel 是 hybris 的高级顾问, 在Java / J2EE 领域拥有超过10年的管理经验,本文阐述了他在使用自动化工序去构建 Android 应用程序遇到的一些难题,大家不妨读读,希望能有所收获。

以下系译文:

在我目前的工作中,我必须使用一些自动化工序去构建 Android 应用程序。这篇文章的目的就是描述我所遇到的难题,避免读者在这个过程浪费更多时间。目的就是分享我在这一过程中所遇到的困难,为读者提供前车之鉴,从而节省宝贵的时间。

环境搭建如下:

  • 使用 Puppet 搭建基础设施
  • 使用 Jenkins 搭建 CI 服务器
  • 工程文件
  • 来构建主体
  • 作为主要测试工具

Puppet and Jenkins

事实上,我的准备工作已经相当完备。同事们已经使 Jenkins 服务器可以自动安装,以及准备好了所需的软件包——包括 Java 和已提供的可复用的 Puppet 类。Jenkins 的工作完全依赖于一个单一 config.xm 文件,即不同部分的封装。每部分都由一个专门的模板处理。因此,在我看来,创建一个简单的 Gradle 任务就如同在公园里散步一般轻松,最多几天时间便可以完成。

第一步非常容易:只需一个最新版 Puppet 清单,能帮助你添加 Gradle 插件到 Jenkins 服务器。

The Gradle wrapper

如果你是我博客的忠实读者,那你大概知道我对 Gradle 的看法。不过,我必须得承认,Maven 的确缺乏这种兼容性,即不论安装哪个版本的工具都确保编译成功——虽然它应该具备该功能。为了实现这一目标,Gradle 通过提供一个 JAR、一个 shell 脚本和一个属性文件,属性文件还包含了从 URL 到 Gradle ZIP 的分发,组装成所谓的包装机制。这三个需求都被存储在 SCM 中。

然而这正是麻烦的开始。在一个企业环境中进行下载,意味着要通过和验证代理。最简单的选择莫过于在工作配置下设置好一切,包括代理凭证。然而,从安全的角度来看,这样的做法并不理想,因为任何人访问 Jenkins 接口或文件系统,都能够读取这些凭据。显然,我们需要一个更好的方式。

用户已经拥有了配置代理完备的 Nexus 库。上传所需的 Gradle 分布,并更新指向它的 gradle.properties,简直易如反掌。

The Android SDK



Android SDK 只是一个 ZIP 文件。我用同样的方法:先下载文件然后将其上传到 Nexus。这一步之后,一个 Puppet 脚本会负责下载、提取,并为它设置正确的权限。

然而,事情并没有想象的那么简单。Android 开发者都知道,Android SDK 需要手动操作:开发者必须手动检查所需平台和工具,并将其下载在本地文件系统。这看上去很简单不是吗,但如果转为自动操作则会让很多开发者头疼,尽管有一个命令行相当于可以通过 SDK「带有 --no-ui 参数」来安装/更新包。如果你想了解更多,请点击这里

谷歌工程师未能提供的两个重要参数:

  • Proxy credentials – login/password
  • Accepting license agreements

为了解决这一问题,网上有很多蹩脚的方案,最诱人的应该要数配置文件了,但我却发现它们没多大用。然而,通过 expect 命令的使用,我反而发现了一种创造性的解决办法。Expect 是一个漂亮的命令,用来读取标准输出,并用标准输入进行相应的填写。值得一提的是,它竟然还可以接受正则表达式。所以,在请求代理登录时,你键入登录名、填写密码,当它要求许可证接受时,你键入「同意」就能轻松搞定。虽然我反复多次试验,历经很多错误,才达到预期结果。但这个方法非常简单、直接。

我最初的设计是,使所有可能用到的装有 Puppet 的 Android 包,成为服务器配置的一部分。在标准化操作中「如文件创建或系统包安装」,Puppet 可以确定这项配置是否必要。例如:如果某文件已经存在,那就没有必要再重复创建了。在最后的 Log 中,Puppet 会报告它执行的每一个操作。起初,我试图通过在配置过程中,人为地告诉 Puppet 哪个包是已配置的,因为 Android SDK 为每个包都创建一个文件夹。但要命的是,Puppet 只接受单一文件夹来验证。对于某些包来说,并没有任何版本信息「例如 Google 游戏服务」。

因此,一个同事提出将 Puppet 配置的更新,移动到每个任务的预先步骤中。这样能修复非幂等问题,同时,还能在每个任务中更新所需配置。

Robolectric



说到这里,我本以为一切都搞定了。但非常不幸,并不是这么回事,就因为这个库—— Robolectric。

此前,我对 Robolectric 没什么了解,只知道这是一个测试库,能够在 Android 上运行测试,而无需任何物理设备的连接。在 Jenkins 上试图编译时,我偶然发现了一个「有意思」的问题:尽管 Roboletric 提供了一个具有完整依赖性的 POM, 但 MavenDependencyResolver 类硬编码库应该从哪里下载?

唯一的解决办法是通过扩展上面的类来实现。我用的就是上面提到的企业 Nexus 库。

上传并发布任务

为了实现前面的任务,我只需添加一个自定义 Gradle 任务,从 settings.xml 得到 Nexus 设置「由 Puppet 调配」。基于此,我成功地上传了任务。最后,对于每个任务执行的型号,我添加到所上传的工件集的输出文件中。因此,不管编译文件是哪种型号配置,下面的命令都将只上传 XXX 和 YYY:

 ./gradlew assembleXXX assembleYYY upload

上面的任务都搞定了,那发布岂不是更简单:唯一需要的就是设置 Gradle 插件,它添加了一个发布任务,类似于 Maven 的 deploy。

结束语

作为后端开发人员,我已经习惯于持续集成设置,毫无疑问,我可以在几天内搞定 Android CI 的进程。对于 Android 系统在 CI 上的欠缺,我觉得不可思议。每一步都苦不堪言,糟糕的记录「如果有的话」和解决方案似乎更像黑客般具有破坏性。如果你想沿着这条路走下去。呐,别说我没告诉你……Good Luck!

原文链接: Fully Automated Android Build

本文系 OneAPM 工程师编译整理。OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读更多技术文章,请访问 OneAPM 官方博客

全自动化的 Android 编译管线的更多相关文章

  1. 6.6 Android 编译机制的变迁

    我们使用Java开发android,在编译打包APK文件时,会经过以下流程 Java编译器将应用中所有Java文件编译为class文件(JVM运行的是.class文件,而DVM是.dex文件) dx工 ...

  2. [Android 编译(一)] Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程

    本文转载自:[Android 编译(一)] Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程 1 前言 经过3天奋战,终于在Ubuntu 16.04上把Android 6. ...

  3. 【Linux】CentOS下升级Python和Pip版本全自动化py脚本

    [Linux]CentOS下升级Python和Pip版本全自动化py脚本 CentOS7.6自带py2.7和py3.6 想要安装其它版本的话就要自己重新下载和编译py其它版本并且配置环境,主要是软链接 ...

  4. Android编译优化系列-kapt篇

    作者:字节跳动终端技术---王龙海 封光 兰军健 一.背景 本文是编译优化系列文章之 kapt 优化篇,后续还会有 build cache, kotlin, dex 优化等文章,敬请期待.本文由Cli ...

  5. Android编译环境折腾记

    题记:感觉是时候写点什么了=_=! 第一次安装了ubuntu14.04.5,官网下载的iso,官网下的jar,编译android4.x需要安装jdk6,更高的版本会有问题,baidu到很多搭建环境的步 ...

  6. Cocos2d-x3.6 Android编译问题

    在Cocod2d-x论坛上看到越来越多人吐槽新版本更新太快,改动太大,而且经常有BUG导致升级要折腾很久很久..但我就是喜欢折腾,喜欢升级到最新版本,看看有了哪些新功能,哪些改进.为此也折腾了不少,遇 ...

  7. Xamarin.Android编译CPU类型选择方式

    Xamarin.Android编译CPU类型选择方式 在Xamarin.Android编译的时候,默认提供了5种CPU类型供大家选择.它们分别为armeabi.armeabi-v7a.arm64-v8 ...

  8. Xamarin.Android编译提示找不到mscorlib.dll.so文件

    Xamarin.Android编译提示找不到mscorlib.dll.so文件 错误信息:AOT module ‘mscorlib.dll.so’ not found: Cannot load lib ...

  9. Android编译过程详解(一)

    Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...

随机推荐

  1. 远程连接数据库(通过pgAdmin)

    1.编辑/var/lib/pgsql/data/pg_hba.conf,增加语句  host all all 192.168.105.225/36 trust 让数据库接受网络 192.168.105 ...

  2. Linux环境PostgreSQL源码编译安装

    Linux环境PostgreSQL源码编译安装 Linux版本: Red Hat 6.4 PostgreSQL版本: postgresql-9.3.2.tar.gz 数据存放目录: /var/post ...

  3. 在VS2010 SP1基础上安装mvc3

    安装VS2010 SP1后,再安装mvc3会报错,估计原因是此安装包会安装VS的补丁,而sp1的补丁版本高过此安装包的. AspNetMVC3ToolsUpdateSetup.exe 解决办法: 运行 ...

  4. AppCan移动平台开发常见问题解答

    在使用AppCan移动平台开发跨平台APP时,有开发者会遇到一些问题, 不急,跟笔者一起来聊一聊使用AppCan平台开发中常见问题的解答方法. 问1.正常是按照官网提供的4个iphone启动图尺寸来做 ...

  5. Android--简单开发和使用ContentProvider数据共享

    今天学习的时候学到了ContentProvider数据共享这个东东,所以自己写了个小例子: 我们要开发ContentProvider的话,需要创建一个类去继承ContentProvider,里面会让你 ...

  6. Java求职面试准备之常见算法

    最近在求职面试,整理一下常见面试算法: 对TestAlgorithms.java中方法的测试见JunitTestAlgorithms.java(引入了junit4) 1.TestAlgorithms. ...

  7. WCF 已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性

    我出现这个问题主要是服务器返回数据量过大引起了,需要客户端服务端都要进行配置:我会说其实有神器的么....(工具=>wcf服务配置编辑器),用工具编辑下,就会完全搞定这个问题,再也不用纠结了 服 ...

  8. Go中的指针与函数接收器

    Go中使用*号表示指针,但是没有指针算数,不能对其进行加减.同时内存管理都由Go来负责,不需要拖动释放内存. Go中的函数接收者,可以为值类型,也可以是引用类型. 看代码: package main ...

  9. [转]VC的DDK编译环境构建

    [转]VC的DDK编译环境构建 http://blog.csdn.net/skdev/article/details/1336935   1 环境状况 Windows XP SP1 NTDDK(win ...

  10. 防止被dylib hook的小技巧

    在Build Settings中找到“Other Linker Flags”在其中加上”-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null”即可.