Gradle for Android(八) 建立持续集成

持续集成【Continuous integration (CI)】是一种开发实践,它要求团队的开发人员定期集成他们的工作,经常每天进行几次。向主仓库的每个push由自动化构建进行验证。这种实践有助于快速发现问题,从而加快开发速度,提升代码质量。伟大的Martin Fowler写了一片文章来讲解这个概念,描述最佳实践http://martinfowler.com/articles/continuousIntegration.html

为Android设置CI有几种选择。用的最广泛的有Jenkins,TeamCity,Travis CI。Jenkins拥有最大的生态系统,大约有1000个插件。它是开源的,有大量的贡献者。TeamCity是JetBrains的一个产品,该公司同样创造了IntelliJ IDEA。Travis CI相对比较新,主要用于开源项目。

我们将研究这些CI系统,以及如何同Gradle协同工作。在本章末尾,我们会提及一些Gradle技巧,使CI更加容易。

本章内容有:

  • Jenkins
  • TeamCity
  • Travis CI
  • 进一步自动化

Jenkins

Hudson最初由Sun公司于2005年发布,那是Jenkins的原型。这些年,它逐渐成为了Java社区最流行的CI系统。Sun被Oracle收购不久,Oracle和Java社区关于Hudson有了冲突。在无法解决的情况下,社区继续以Jenkins为名称运行该项目,因为Hudson被Oracle所有。

Jenkins的强大在于它的插件系统。任何人对构建系统有新功能的需求,都可以创建插件来扩展Jenkins的能力。这也是为什么为Android应用或者库配置一个自动化构建如此简单的原因。

配置Jenkins

如果你的电脑还没有安装,可以在https://jenkins-ci.org下载。

在使用Jenkins之前,你需要确保已安装了所有构建Android app和library所需的库。构建任何Java相关的东西,你需要安装JDK。

你同样需要确保安装了Android SDK和build tools。你不必在构建服务器上安装IDE,除非你打算打开项目。

在Java和Android SDK安装后,你需要在Jenkins中配置它们。首先需要用浏览器打开Jenkin的首页,点击Manage Jenkins|Configure System,滚动到Global properties。添加ANDROID_HOME,JAVA_HOME这两个环境变量,分别指向android SDK目录和java目录。

图1

你还需要安装Gradle插件。点击Manage Jenkins|Manage Plugins,打开Available标签,搜索Gradle。定位到Gradle插件后,选择选框,点击Download now and install after restart。该插件可以创建Gradle相关的构建步骤。

构建配置

安装了所有需要的东西后,你就可以在Jenkins中创建一个CI工程了。首先你需要设置VCS仓库,这样Jenkins才知道去哪里找项目的源码。你可以基于库的事件来设置Jenkins自动构建Android app或者library,也可以使用触发器或者手动构建。为了开始真正的构建,你需要调用Gradle脚本来添加一个新的构建步骤。你可以配置Jenkins使用Gradle Wrapper。使用Gradle Wrapper不仅可以避免手动安装Gradle,还可以确保Gradle自动更新。选择Make gradlw executable也是非常好的。这解决了Windows系统创建的项目,执行Gradle Wrapper的权限问题。

你可以为构建步骤输入一个描述,并可以选择打开两个开关:info,stacktraceinfo用来打印构建过程的信息,这在排查错误时非常有用。如果构建出现了异常,stacktrace开关会打印出异常的堆栈信息。有时你可能需要更加详细的信息,这时你可以打开full-stacktrace开关。

为了完成配置,你需要指定想要执行的Gradle任务。首先,执行clean任务,确保没有上一个构建的残留输出。其次,执行build任务,这会触发所有构建变体进行构建。Jenkins配置如下:

图2

保存项目配置后,就可以构建了。

如果你的构建服务器安装在64位的Linux系统上,可能出现异常java.io.IOException:Cannot run program "aapt": error=2, No such file or directory。这是因为AAPT是32位的程序,在64位系统上运行需要额外库的支持。可以通过如下命令安装所需的库:

$ sudo apt-get install lib32stdc++6 lib32z1

如果构建没有问题,它会为所有的构建变体创建一个APK。你可以指定Gradle任务来分发这些APK。在本章末尾我们会提及自动分发,因为这是每个构建系统都有的。

TeamCity

与Jenkins不同,TeamCity是一个专卖产品,只对开源项目免费。它由JetBrains公司制作和管理。TeamCity内置支持Gradle Android构建。

设置TeamCity

如果你还没有安装TeamCity,可以去JetBrains官网下载(https://www.jetbrains.com/teamcity)。

为使TeamCity可以构建Android app或者library,你需要确保安装了JDK,Android SDK以及Android build tools。你同样需要将ANDROID_HOME添加到电脑的环境变量中。

与Jenkins不同的是,TeamCity不需要任何插件来触发Gradle构建,TeamCity内置支持运行Gradle。

构建配置

你需要创建一个新的项目来配置Android构建。你仅需要提供一个名称。创建了项目,就可以进行配置了。首先,你需要添加一个VCS根目录,这样TeamCity就可以找到项目的源码了。然后你需要创建一个新的构建配置。你同样需要将VCS跟目录绑定到构建配置中。设置好这些,你就可以添加一个新的构建步骤。如果你点击了Auto-detect build steps按钮,TeamCity会尝试选择必需的构建步骤,这基于项目的内容。在基于Gradle的Android项目中,配置结果去下:

图3

TeamCity检测到项目使用了Gradle,并且Gradle Wrapper可用。你仅需要选择Gradle构建步骤,并将其添加到构建配置中。如果你不需要做其他任何过多的事情,这些足够确保构建你的Android app。你可以测试配置,只需要打开项目预览,点击Run...按钮。

Travis CI

如果你的项目仓库托管在GitHub上,你可以使用Travis CI进行自动构建。Travis CI(https://travis-ci.org)是一个开源的托管持续集成系统,对开源仓库免费。它对私有仓库是收费的,本书只讨论免费的情况。

Travis会检测新的提交,并自动开始一个新的构建。Travis默认构建所有分支,不仅仅是主分支。它同样会自动构建pull request。

由于Travis在内部工作,你无法配置构建服务器本身。你需要创建一个新的配置文件,包含所有的Travis构建你的app或者library的信息。

构建配置

如果你想使用Travis构建你的项目,你首先需要登录Travis CI,并连接到你的Github账户。做好了这些,你需要在设置中选择你想构建的项目。

为了配置构建过程,Travis要求你创建一个名为.travis.yml的文件,包含整个配置。为了配置Android项目,你需要添加一些Android特有的属性:

language: android
android:
    components:
    # The build tools version used by your project
    - build-tools-22.0.1

    # The SDK version used to compile your project
    - android-22

    # Additional components
    - extra-android-m2repository

语言设置指定你想要运行的构建过程。上述情况下,你在构建一个Android app。Android特定属性包含构建工具版本和Android SDK版本。Travis会在执行build任务之前下载这些东西。如果你使用了support library或者Google Play Services,你需要明确指定,因为Travis也需要去下载这些依赖。

Travis并不强制要求配置build tools和SDK版本,但是确保它们的版本和你在build.gradle文件定义的版本一致,会使你遇到更少的问题。

如果你在windows系统创建一个Android项目,Gradle Wrapper可能会有一些权限问题。所以,最好在运行真正的构建脚本之前解决它。你可以添加一个预构建步骤:

before_script:
    # Change Gradle wrapper permissions
    - chmod +x gradlew

为了开始构建,需要将一下代码添加到Travis的配置文件中:

# Let's build
script: ./gradlew clean build

这段代码会运行Gradlw wrapper,执行cleanbuild任务。

当你完成了Travis构建配置后,你可以向项目的Github仓库提交和推送文件。如果配置都正确,Travis会启动构建过程,你可以在Travis网站上看到。一个成功的构建如下所示:

图4

Travis在构建后还会发送一封邮件报告。如果你是一个经常收到pull request的开源库的维护人员,这会非常有用。

你会很快注意到Travis有一个缺点,那就是速度。Travis并没有给你一台特定机器,而是为你触发的每个构建启动一个Vanilla virtual machine(VVM)。也就是说,对于每个新的构建,Travis在构建app或者library之前,需要下载安装Android SDK和构建工具。

从好的方面看,Travis是免费和开源的,这使它对于开源项目非常完美。Travis会自动构建pull request,使你及时知晓有人为你的代码提交了补丁。

进一步自动化

大多数时下的持续集成系统支持Gradle,或是内置支持,或是通过插件支持。这意味着除了仅仅构建你的app或者library,你还可以创建所有的Gradle任务,来进一步自动化你的构建。使用Gradle任务定义额外的构建步骤,而不是通过CI系统,其优势在于额外的构建步骤会变得更加便捷。在你的开发机器上运行自定义的Gradle任务非常简单。从另一方面看,一个自定义的Jenkins构建步骤,可以在Jenkins没有安装的情况下运行。在一个特定的CI系统有额外的构建步骤使得向其他CI构建系统进行移植变得非常困难。Gradle任务也可以非常简单的移植到不同的项目中。在本节,我们会讨论几种方式来使用Gradle任务和插件,进一步实现自动化构建和部署app和library。

SDK管理器插件

你可能会在某个时候遇到一个问题:构建服务器上的Android SDK不是最新的。当你的app或者library升级SDK版本时,你同样需要在构建服务器上安装新的SDK。如果你有多个构建代理,这会非常麻烦。

感谢社区的努力,有一个Gradle插件会检查构建所依赖的Android SDK版本是否可用,如果不可用,插件会自动下载。

SDK管理器插件不仅会下载构建配置文件指定的编译SDK,也会下载正确的build tools和platform tools版本。如果你的项目依赖于support library或者Google Play Services,该插件也会下载它们。

SDK管理器插件是一个开源插件,你可以在GitHub找到源码(https://github.com/JakeWharton/sdk-manager-plugin)。

运行测试

如果你想在构建期间运行单元测试(JUnit或者Robolectric),你只需要向Gradle的执行阶段添加相应的任务。如果你想运行任何的功能测试,你需要模拟器来安装app,所以你可以使用gradlew connectedAndroidTest来运行测试.

如果你使用Jenkins,有一个名为Android Emulator Pluginhttps://wiki.jenkins-ci.org/display/JENKINS/Android+Emulator+Plugin)的插件,可以用来为每个构建启动一个模拟器。TeamCity同样有一个活跃的插件生态系统,有一个名为Android Emulator的插件可以向Jenkins插件一样用来设置模拟器。你可以在TeamCity插件官网(https://confluence.jetbrains.com/display/TW/TeamCity+Plugins)找到它。

Travis CI也可以启动一个模拟器,但这是一个实验功能。如果你使用它,将下面的代码片段添加到你的.travis.yml配置文件中:

# Emulator Management: Create, Start and Wait
before_script:
    - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
    - emulator -avd test -no-skin -no-audio -no-window &
    - android-wait-for-emulator
    - adb shell input keyevent 82 &

android-wait-for-emulator指令告知Travis等待模拟器的启动。模拟器启动后,adb shell input keyevent 82 &会执行,从而解锁屏幕。之后,就可以运行测试了。

持续部署

为了帮助开发者自动部署Android app,Google发布了Google Play Developer API,一个以编程方式将APK发布到Google Play的API(https://developers.google.com/android-publisher)。这个API使你不必再打开浏览器,登录Google Play,然后使用web接口上传APK。你不必再基于Google Play Developer API创建自己的发布脚本,而只需要在成功构建之后,在构建系统中使用众多插件中的一个来向Google Play推送APK。

Jenkins有一个名为Google Play Android Publisherhttps://wiki.jenkins-ci.org/display/JENKINS/Google+Play+Android+Publisher+Plugin)的插件可以为你做这些。然而,一个更好的选择是使用Gradle插件,这样你就可以在任何设备,任何类型的持续集成系统中运行发布任务了。Android社区的某些人创建了基于Google Play Developer API的Gradle任务来帮助配置整个发布过程。你可以在GitHub(https://github.com/Triple-T/gradle-play-publisher)找到Gradle插件Gradle Play Publisher的源码。它也发布在了Maven Center和JCenter上。

为了使用该插件,需要在顶级构建文件中添加如下语句:

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'com.github.triplet.gradle:play-publisher:1.0.4'
    }
}

然后在你的Android模块的配置文件中应用这个插件:

apply plugin: 'play'

应用了Gradle Play Publisher插件后,你会有几个新的可用任务:

  • publishApkRelease上传APK和最近的变更
  • publishListingRelease上传描述和图片
  • publishRelease上传所有东西

如果你有不同的构建变体,你也可以运行特定变体的版本,比如publishApkFreeReleasepublishApkPaidRelease

为了访问Google Play Developer API,你需要设置一个服务账户。这个设置超出了本书的范围,但如果你想使用Gradle Play Publisher,这是必需的。你可以在https://developers.google.com/android-publisher/getting_started得到帮助。

在你创建了服务账户后,你可以在构建配置文件中添加证书:

play {
    serviceAccountEmail = 'serviceaccount'
    pk12File = file('key.p12')
}

play块中包含Gradle Play Publisher插件特有的属性。除了服务账号证书,你还可以指定APK的发布途径:

play {
    track = 'production'
}

默认的途径是alpha,你可以修改为beta或者product

Beta分发

有很多Android app的beta测试,比如Google Play商店的bata途径。另一个是Crashlyticshttps://crashlytics.com),与Gradle有很好的集成。Crashlytics的团队创建了这个自定义的插件,不仅可以创建新的Gradle任务来向他们的平台发布构建,还可以与Android插件任务挂钩来操作ProGuard映射。

你可以按照网站的步骤来使用Crashlytics。设置好后,它就会与你的构建挂钩。Crashlytics插件暴露了一个名为crashlyticsUploadDistributionInternal的任务,可以用来将APK上传到Crashlytics。为了推送一个新的app版本,你首先需要使用build或者assemble任务来进行构建。APK准备好后,你可以使用crashlyticsUploadDistributionInternal任务将它上传到Crashlytics。Crashlytics插件为每个构建变体创建了一个上传任务。

自定义Gradle插件使开发者们可以很容易地使用Crashlytics,也使你很容易将你的测试构建上传到Crashlytics,因为你只需要在构建构成中执行一个额外的任务。这是一个恰当使用Gradle强大之处,以及一个好的Gradle插件使编程变得简单的的很好的例子。

推荐阅读更多精彩内容