Jenkins-ci容器化在Android项目构建中的应用
随着软件开发复杂度的不断提高,如何能在不断变化的需求中快速适应和保证软件的质量显得尤其的重要,持续集成正是针对这一类问题的一种软件开发实践。
本文中的Jenkins-ci
容器化方案能够在项目构建过程中提取出更多自定义的需求信息并进一步将持续集成的环境参数配置标准化。
因此,在项目的构建过程中,我们对用户比较关心的信息(如代码质量、apk
方法数和大小、资源文件变化、代码提交记录等)进行跟踪、收集、分析和统计,并将结果以图表的形式在通知邮件中展现给用户,让用户对项目的迭代情况有更多的了解。
1. Jenkins配置以及构建通知邮件内容定制
1.1 Jenkins安装、配置与使用
关于详细的Jenkins安装、配置与使用说明,可参考文章Jenkins工具(一)之 Jenkins集成android工程
和Jenkins工具(二)之 Jenkins集成android工程,文中不再详细叙述。
其中,构建中使用到的插件几个主要插件:
- Git plugin Git工具集成
- Gitlab Plugin和Gitlab Hook Plugin 支持Gitlab项目构建
- Gradle plugin Gradle工具集成
- Email Extension Plugin 构建结构邮件通知
- Git Changelog Plugin 获取Git提交记录
- Android Lint Plugin 收集分析Android Lint检查结果
- FindBugs Plugin 收集分析FindBugs检查结果
- HTML Publisher plugin 支持HTML报告
1.2 构建结果邮件定制
完成Jenkins
的安装以及环境参数配置后,新建一个项目用于构建,项目构建完成后需要将结果内容通过邮件的方式通知用户。将构建结果通知到用户的邮件内容的定制,则是本次实践的重点。
本次自动化构建将包括以下几个内容:FireLine
(源码检查)、Android Lint
、FindBugs
(Class文件检查)、Apk
包大小和方法数统计、资源文件统计,以及Git commit
日志分析。
1.2.1 Email Extension 配置
构建结果邮件内容定制依赖于前面提到的Email Extension Plugin
,该插件目前支持Jelly
和Groovy
两种语法编写模板,本文的模板内容定制将采用Groovy
(个人认为Jelly
标签不够灵活)。同时,创建的模板文件要放在Jenkins
根目录下的email-templates
文件夹下。模板文件配置如下:
|
|
另外,想要在模板中获取构建结果信息,可以通过获取Jenkins
环境中的Action
对象来实现。Action
是插件用来在Job
或Build
页面增加功能的一种主要方式,是Jenkins
最常用的一个扩展点。如org.jenkinsci.plugins.android_lint.LintResultAction
、hudson.plugins.findbugs.FindBugsResultAction等,后文将多次用到。
1.2.2 Android Lint
Android Lint
是一个静态代码分析工具,它能够对你的Android
项目中潜在的bug
、可优化的代码、安全性、性能、可用性、可访问性、国际化等进行检查。支持自定义Lint规则,可参考文章浅谈Android自定义Lint规则的实现 (一)、浅谈Android自定义Lint规则的实现 (二)。
安装插件Android Lint Plugin
后,进入项目的配置页,并添加构建后操作Publish Android Lint results
,根据页面提示设置参数,若不设置参数,则使用默认参数。同时,在Invoke Gradle Script
的Task
中添加对应的lint
检查任务。
通过阅读 android-lint-plugin 的源码可知,只要获取org.jenkinsci.plugins.android_lint.LintResultAction对应的Action
实例,就可以得到lint
检查的数据。
最终,邮件中的显示结果如图:
点击链接地址,会跳转到Lint Issues
的包含图文描述的界面,如图:
不过需要注意的是,默认情况下,在Gradle
插件com.android.application
的android
对象中,lintOptions
的abortOnError
参数为true
,在执行lint
命令时,遇到错误即中止构建。因此,若希望lint
执行出错后继续构建,则需要将该参数置为false
,可以在build.gradle
文件中动态修改:
|
|
1.2.3 FindBugs
Findbugs是一个静态分析工具,用来查找Java
代码中的程序错误,将字节码与一组缺陷模式进行对比以发现可能的问题,并根据其可能产生的影响或严重程度,而对开发者的提示。并且,这组缺陷模式是可配置的,通过配置可以过滤掉一些我们不想或不需要检测的问题。
FindBugs
和Android Lint
的集成方式基本一致。在安装插件FindBugs Plugin
后,进入项目配置页,并添加构建后操作Publish FindBugs analysis results
,根据页面提示设置参数,若不设置参数,则使用默认参数。同时,在Invoke Gradle Script
的Task
中添加对应的findbugs
检查任务。
|
|
结合findbugs-plugin的源码可知,只要获取hudson.plugins.findbugs.FindBugsResultAction对应的Action
实例,就可以得到分析结果。最后,在邮件中的显示结果如图:
点击链接地址,同样跳转到FindBugs
的图文界面。
1.2.4 动态集成自定义的gradle任务方案
在项目持续集成时,我们需要添加一些自定义的任务,但是又要尽量避免修改用户的项目代码。因此,本文采用了一个比较折中的方案:
在Jenkins
的根目录下建一个configs
文件夹,放置一些项目构建过程使用的第三方库、脚本以及配置文件等;然后在项目构建之前,通过执行Job
配置页的脚本将该文件夹及其内容复制到目标构建项目的工作空间中,同时修改项目的build.gradle
文件;最后在项目构建过程中,调用这些第三方库、脚本以及配置文件,来完成自定义的额外的构建任务。
FindBugs
任务的集成就应用了上述方案,后续介绍的FireLine
集成以及Apk
大小、方法数和资源文件统计的集成亦是如此。
例如,修改build.gradle
文件,动态引入jenkins.gradle
文件:
|
|
1.2.5 FireLine
FireLine 提供一种静态代码(指java
源码,后来据说又支持class
文件)扫描服务,基于PMD
开源。它是360公司针对自己的产品定制的安全检查规则,使用这些规则对源代码进行扫描检测,找出代码潜在的安全风险。目前,对外也可以使用。因此,本文对该工具进行了集成。
FireLine 对外提供一个jar
包,必须通过命令行的形式运行,因此需要添加一个fireLine
的任务:
|
|
构建后,检查结果在邮件中显示如图:
点击链接地址,跳转到需要HTML Publisher Plugin
支持的火线检查的详细界面:
注意,若FireLine
报告不能正常显示,这是由于它使用了JavaScript
,这里需要设置jenkins
允许脚本执行(allow-scripts
),需要在系统设置页的Jenkins Script Console
选项中输入命令:
|
|
并执行,从而修改Jenkins
的默认配置参数,然后重新构建项目即可。
1.2.6 Apk方法数、大小以及资源文件分析
随着项目的不断迭代更新,android
应用不得不面对64k
方法数限制、Apk
体积不断变大的问题。因此,本次实践中将对该类数据进行收集分析,更加直观的展现给关注该类信息的用户。
1.2.6.1 Apk方法数、大小统计
在Apk方法数统计集成中,采用了开源的Gradle
插件项目-dexcount-gradle-plugin,该插件会根据配置为打包的每个Apk
文件生成一份方法数统计的文件。
|
|
配置完成后,执行assemble
任务时,会在app/build/outputs
目录下生成apk
方法数统计数据文件:
因此,在本次jenkins-ci
实践中,我们需要做就是在构建项目中动态添加该插件,并将该插件生成的统计数据进行收集、转换。
和集成findbugs
插件不同的是,这里还需要动态修改app
项目的buildscript
对象,并保证该插件是在com.android.application
之后被应用。
|
|
并通过调用gradle
中的PluginManager
对象的void withPlugin(String id, Action<? super AppliedPlugin> action)
方法,来监听插件的添加事件。当com.android.application
插件被添加时,就可以动态添加dexcount-gradle-plugin
插件。
|
|
最后,为了在jenkins
中使用该数据,创建一个apkMethodCounts
任务将上述的所有的json
格式文件进行统一解析转换,并将解析结果和生成的Apk
文件–对应起来。构建结果如图:
1.2.6.2 资源文件大小统计
资源文件统计插件resource-size-plugin与dexcount-gradle-plugin
的使用方法基本一致,该插件也是需要通过动态添加。
插件配置完成后,执行resourcesize
任务,会在app/build/outputs
目录下生成分析结果resoucesize.txt
。其中,第一行表示所有资源文件的总大小,后面每行代表单个文件最大的文件名称以及文件大小:
最后,将数据进行简单处理,在jenkins
的构建结果中显示如图:
1.2.7 Git Changelog分析
随着项目的迭代,代码的提交越来越频繁,代码的管理显得越来越重要。而commit message
是开发者是对自己所提交代码的唯一说明,它能够直接反映开发者的意图,并方便快速查询和浏览,是必不可少的。在这些commit message
中,比较重要的主要有feature
(新功能)和bug fix
(问题修复)两种类型,也是一个产品的关注点。
因此,为了在构建中提取该类信息,在参考网上的一些Git
规范的基础上,整理出一份Git提交规范,规定了完整的git
提交日志由信息头部、信息主体和信息尾部构成,其中信息头部需要包含类型、范围和主题三类信息。
|
|
详细规范描述可参考规范文档。另外,Commitizen是一个撰写合格Commit message
的工具,很好用,推荐~。使用该工提交代码之后,会自动生成上述格式规范的日志信息。
通过Commitizen
工具(或者手动)提交之后,在GitLab
上生成的Commit message
如图:
从图中的示例可以看出,两个Commit message
的类型是feature
和bug fix
的,因此Jenkins
构建的过程中需要进行处理并显示给用户。

另外,为了能够解析bug fix
类型提交中的jira
上的问题并生成跳转链接,需要在项目根目录下添加一个jenkins.xml
文件,示例如下:
|
|
综上,关于自定义Jenkins-ci
构建通知邮件内容的部分已经介绍完了,下面我们要讲一下Jenkins
与Docker
结合如何实现快速配置。
2. Jenkins与Docker结合实现快速配置
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux
机器上,也可以实现虚拟化。基于Docker
轻量级、可移植的特点,本次实践将Jenkins-ci
的构建环境配置打包到Docker
中,从而实现快速配置。
2.1 Dockerfile文件配置
创建一个自定义的docker
镜像,可以通过Dockerfile
描述文件来自动完成。Dockerfile
文件包含了创建镜像所需要的全部指令,可以使用Docker build
命令来创建镜像。
本文中使用的Dockerfile
是基于jenkinsci
开源的jenkins镜像,并根据需求进行了定制,部分内容如下:
|
|
在配置文件中,我们使用wget
命令去官方下载最新的linux
下android SDK
包,并配置环境,然后使用android
命令选择和自己项目匹配的SDK
以及工具的版本(本次打包的镜像下载了android-23
以及系列的编译工具,用户可根据需求自行修改)。
2.2 使用Dockerfile文件构建镜像
由于Docker
是基于Linux
,在Mac OS
上运行起来需要一个虚拟的Linux
环境,它还需要若干工具支持:
- VirtualBox:虚拟机,用来运行
Linux
- docker-machine:用来管理虚拟机
- docker:
Docker
本身 - docker-compose(Mac OS only):用来管理多个
docker
容器 - Kitematic:用来管理远程
Docker Hub
上述工具安装完毕后(推荐使用Homebrew),就可以创建虚拟机,配置docker
环境:
|
|
然后,进入到Dockerfile
所在的目录,就可以执行build
命令打包镜像:
|
|
更多内容可参考网易蜂巢使用指南。
综上,本次Jenkins-ci
容器化实践就讲完了~有问题或建议可以联系我,一起交流~
3. 参考资料
- jenkins官网
- jenkins插件
- Jenkins集成android工程
- jenkins-ci
- jenkins的Api文档
- Jenkins构建Android项目持续集成之findbugs的使用
- dexcount-gradle-plugin
- FireLine
- email-ext-plugin
- findbugs-plugin
- Android中使用FindBugs
- Commit message和Change log编写指南
- git-changelog-plugin
- 持续集成之Jenkins插件使用-邮件通知模板化
- 搭建linux(ubuntu 14.04)下的android开发环境
- Ubuntu下全命令行搭建Android开发环境
- Run Docker on your Mac
- 搭建Android持续集成服务器