Android Jenkins集成(自动化打包)

作为一名Android程序猿,能偷懒时是一定要偷懒的。
大家在开发中一定遇到过:
测试说:帮我打个包吧,
产品说:帮我打个包吧,
......说:帮我打个包吧
此时的你,正思绪如潮的构思着逻辑,激情的敲着代码。。。。。。
看完这篇文章以后,你可以直接对着他们说:自己玩去吧,我这忙着呢!
jenkins可以让所有人都体验到自己打包的乐趣!
先给大家看一下效果图:

123.png

这里先奉上2篇参考的文章地址:
http://www.jianshu.com/p/38b2e17ced73
Jenkins+ Git + Gradle + 二维码生成,二维码与下载链接使用本地Tomcat作为服务器,超详细!!!
http://blog.csdn.net/mabeijianxi/article/details/52680283
郭霖原创,Jenkins+ Svn + Gradle + 蒲公英二维码生成 + Python

下面开始我们的Jenkins之旅:

一.安装(下面安装的,均是指安装在Jenkins服务器下的)

首先到Jenkins的官网下载https://jenkins.io,点击Download Jenkins按钮会弹出两个版本选择:LTS Release(长期支持版本),Weekly Release(每周更新版本)。首先说一下这两个版本,个人觉得和MIUI的更新类似,一个开发版本一个稳定版,大家可以自行选择,功能上几乎没区别。点击尖角号会弹出操作系统,可以选择对应的操作系统安装,也可以直接下载2.xx.x.war包然后放在Tomcat(下文会详细介绍Tomcat一些功能)的webapps目录,新建Jenkins文件夹再放入。
我选择的是Windows安装版的,首先安装版和war版我都尝试过,功能是没区别的,主要的区别在于目录上,安装版指定安装目录以后几乎所有的东西都会在对应的文件夹下生成,比如Jobs(即存放工程目录),不会在其他磁盘再生成多余的文件夹,而war版放在Tomcat目录下以后,用浏览器打开,所有的东西会在C盘生成.Jenkins文件夹。我自己是有一些强迫症的,喜欢目录整洁,不生成多余文件夹的。还有一个理由就是安装版可以不依赖Tomcat,即使本机没有安装Tomcat,安装版安装完成后依然可以用本机ip:port启动。大家可以自行选择喜欢的版本。
由于安装部分比较简单,就不上图了。
插件
1.进入管理插件
接下来就要说说,Jenkins最强大的部分之一了,那就是插件。Jenkins提供了非常多的插件,几乎你想要的插件全有,前提是你能找的到~官网提供了插件搜索功能,选择Plugins页就可以各种搜索了。
重点来了(敲黑板,啪啪啪~):首次进入,首先要输入一个密钥来进入Jenkins,接下来...接下来...上图

setup.png

一般选择第一项即可,会自动安装推荐的插件,注意:这里并不是所有插件都能安装成功,有的安装失败也不影响,所有的安装完进行下一步就可以了。
But,有时候点击以后会发生下面的情况


setup_error.png

怎么点击Retry按钮依然是错误,这时候不要慌张,咱们选择第一张图中的第二项,进行自己选择,这里系统推荐的插件默认也是选中的,直接点安装即可。But,个别情况依然会出现上图的错误页面,那么解决办法就是:进入自行选择页面,清空选项即所有都不选,然后点安装按钮,进入下一页。
下一页就是创建用户页面,这里建议创建用户,下面提供了Continue as admin按钮也可进入主页,但是后期想创建用户还是很麻烦的,所以建议创建用户。
创建好用户,就可以进入到主页了~选择系统管理->管理插件->可选插件来开始安装我们需要的插件。
2.插件列表
注意:列表中为主要插件,而Jenkins的插件是有依赖关系的,安装一个插件可能要先安装它依赖的插件,否则会安装失败。在可选插件勾选列表中的插件即可,依赖插件会自动下载,是不是很棒。这里也没什么技术含量,但是很耗时,系统管理->插件管理->管理插件->可选插件: 勾选如下插件:
fir-plugin(可选,fir平台上传二维码时)
Subversion Release Manager plugin(可选)
Subversion Plug-in(可选)
Git plugin
Gradle Plugin
Email Extension Plugin
description setter plugin
build-name-setter
user build vars plugin
Post-Build Script Plug-in
Branch API Plugin
SSH plugin
Scriptler
Dynamic Parameter Plug-in 此插件存在Bug,后面详细说
Git Parameter Plug-In配置
插件安装完毕,我们就可以来配置Jenkins了,打包又离我们近了一步。

1.Global Tool Configuration
在系统管理选项中找到Global Tool Configuration进入,如果上面的插件安装成功,在这里会看到三个板块,如图


Global_Tool_Configuration.png

分别是JDK,Git,Gradle板块,分别配置这三个的路径。
JDK:别名=任意,JAVA_HOME=JDK目录
Git:别名=任意, Path to Git executable=Git安装目录\bin\git.exe
Gradle:别名=任意,GRADLE_HOME=Gradle下载目录\Gradle\gradle-2.xxGradle尽量配置多个,因为项目的gradle版本可能不一样,所以需要选择不同的Gradle版本进行编译

这个Gradle的目录,可以是Android Studio默认下载的Gradle目录,在用户目录的.gradle\wrapper\dists文件夹下,但是目录不是很整洁;也可以到http://www.androiddevtools.cn找到gradle资源处下载常用的gradle版本,放到一个指定的文件夹,然后配置路径即可,目录比较整洁。
SVN用户设置类似,不再重复。
2.全局属性
在这里最好配置一下全局属性,这里先说一个,就是配置Android SDK目录,在打包是有可能会出现ANDROID_HOME not found的情况,所以在系统管理->系统设置->全局属性版块勾选上Environment variables选项,然后添加

android_home.png

记得更改值内的路径为本机sdk目录。
注意:这里的键需要和本机环境变量内的Android SDK目录的键一致
真正配置起来可能比较繁琐,遇到一些问题,但是多摸索摸索都会成功,接下来开启步入正题

二.项目打包

1.创建项目
距离开始打包又近了一步,接下来就开始创建新项目了,点击首页的新建,进入下图界面

create.png

给自己的项目起个名字,然后选择构建一个自由风格的软件项目,点击OK按钮,进入项目的配置界面。
2.项目配置
直接选择源码管理tab或者向下滚动找到源码管理,如图;
Git用户:

source_manage.png

选中Git选项,会出现上图的界面,配置Git项目的URL,我测试用的是Github项目,并且传输协议选择的是HTTP,需要选择Credentials选项,选择通行证,第一次需要点击Add添加通行证,如图:

credentials.png

Kind种类选择默认的Username with password,然后在Username和Pasword处分别输入Git账户的用户名和密码,然后滚动到下方点击Add,然后在Credentials中选择我们刚才添加的通行证。

SVN用户:
填写svn项目地址,用户名,密码

image.png

接着滚动到构建Tab,点击添加构建步骤,然后选择Invoke Gradle script,如图:

build.png

然后配置构建时的Gradle版本,和需要执行的任务,如图:


build1.png

这个Tasks是先clean工程,然后打包所有渠道的Release版本,这是Gradle的命令,不多说了。然后点击保存按钮,马上就可以打包了。
3.开始构建
点击保存后,进入项目界面,如图:

project.png

点击左侧菜单栏的立即构建,开始构建项目,这时候Build History版块会出现构建任务列表,点击进入可以查看构建详情页,如图

project_build.png

定制想要的功能
1.参数化构建
在我们打包的时候,我们大多时候不想只是简简单单打一个版本的包,我们想通过配置一下参数,来满足一些需求,比如根据渠道打不同版本的包、根据Tag打不同的包等,下面就来说一下Jenkins参数化构建。
在我们项目中需要配置的选项有:版本(Release 或 Debug),版本号,渠道包,根据Tag打包。另外我们还需要加上打包途径,AS打包还是Jenkins打的包,还要加一个时间戳。所有的参数列出来了,下面就配置Jenkins的参数化构建吧~
在Jenkins项目主页选择配置,进入配置页,在General tab将参数化构建过程选中,如图:

General.png

接下来就可以添加参数了,下面我先列出参数表格:
参数名
参数类型
参数值列表

BUILD_TYPE
Choice
Release or Debug

IS_JENKINS
Choice
true

PRODUCT_FLAVORS
Choice
Xiaomi 、Wandoujia等

BUILD_TIME
Dynamic Parameter
2016-12-21-11-11

APP_VERSION
Choice
1.0.0、1.0.1等

GIT_TAG
Git Parameter
tag1.0.0等

下面直接放我的配置截图:


build_type.png

product_flavor.png

app_version.png

is_jenkins.png

build_time.png

git_tag.png

配置完参数还不算完,我们要在下方构建时候引用,首先找到构建标签处,将Tasks属性值修改为:
clean assemble${PRODUCT_FLAVORS}${BUILD_TYPE} --stacktrace --debug

其中${PRODUCT_FLAVORS}
和&{BUILD_TYPE}
分别对应上面的参数名。配置如图:

build2.png

看了图大家肯定留意到了红色框内的选项而且很好奇吧,这个选项是APP_VERSION、IS_JENKINS、BUILD_TIME需要用到的,因为这三个参数需要注入到Android项目中的配置一样,而红色框中的这个选项可以帮我们侵入到gradle.properties文件中替换值,并且build.gradle文件能够直接引用gradle.properties文件中的属性,所以起到了侵入的效果。下面分别是我的gradle.properties和主项目的build.gradle文件全代码:

//gradle.properties
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.org.gradle.jvmargs=-Xmx1536m# When configured, Gradle will run in incubating parallel mode.# This option should only be used with decoupled projects. More details, visit
#http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
#org.gradle.parallel=true

#代码版本管理
VERSION_NAME=1.0.3
VERSION_CODE=5
IS_JENKINS=false
//build.gradle
def releaseTime() {
    return new Date().format("yyyy-MM-dd")
}

/**
 * 获取本地svn版本号,不准,故本地打包不是用svn版本号
 * @return
 */
def getSvnRevision() {
    new ByteArrayOutputStream().withStream { os ->
        def result = exec {
            executable = 'svn'
            args = ['info']
            standardOutput = os
        }
        def outputAsString = os.toString()
        def matchLastChangedRev = outputAsString =~ /Last Changed Rev: (\d+)/

        ext.svnRev = "${matchLastChangedRev[0][1]}".toInteger()
    }
    return svnRev
}

/**
 * 根据不同平台来获取版本号
 */
def getSvnRevisionByPlatform() {
    boolean flag = "true".equals(IS_JENKINS);
    if (flag) {
        ext.env = System.getenv()
        ext.svnNum = env.SVN_REVISION?.toInteger()
        return "$svnNum"
    } else {
        return getSvnRevision()
    }
}

......
......
applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        def fileName
                        def nowTime
                        if ("true".equals(IS_JENKINS)) {
                            //jenkins的动态参数插件,存在bug,自动构建时无法获取到时间,这里去掉时间
                            //这里的xxxxxx为自己的项目名称
                            fileName = "xxxxxx_v${defaultConfig.versionName}_${variant.productFlavors[0].name}_${getSvnRevisionByPlatform()}.apk"
                        } else {
                            nowTime = releaseTime()
                            //本地获取svn版本号不准,或者需要导入插件,故本地不获取版本号
                            if (variant.buildType.name.equals('release')) {
                                fileName = "xxxxxx_v${defaultConfig.versionName}_${nowTime}_${variant.productFlavors[0].name}.apk"
                            } else if (variant.buildType.name.equals('debug')) {
                                fileName = "xxxxxx_t${defaultConfig.versionName}_${nowTime}_${variant.productFlavors[0].name}.apk"
                            }
                        }
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }

这样在Jenkins打包的时候上面三个参数就会随着选择变化而变化了。
GIT_TAG参数使用配置,只需在源码管理处的Branch引用改为$GIT_TAG
引用参数名,如图:

git_tag_use.png

参数配置完毕,看一下主页面的效果吧,现在立即构建选项变成了* Build with Parameters***,完成图:

build_with_parameters.png

提示:
如果选中了GIT_TAG中的任意版本都无法取消选中,只能刷新;
还有使用GIT_TAG时最好选择tag版本大于等于支持Jenkins打包的版本,因为之前版本代码中没加需要侵入的属性

2.按时打包
由于篇幅原因加上这个功能我没用在项目中,所以请参考使用Jenkins搭建iOS/Android持续集成打包平台配置构建触发器部分。
3.构建命名
每次构建的时候,Build History模块显示是这样的,如图:

build_history.png

每次构建都只显示数字(#xx),这样很不好看,我们想要它显示更多的信息怎么办呢?比如加入构建者姓名、构建的app版本、构建的类型等。请看下图:


set_build_name.png

配置完以后再次打包,变成了这个样子,如图:


build_history1.png

是不是很Nice,当然大家还可以根据需求自行发挥~

5.二维码下载
二维码下载功能,现在网上大多数的做法是通过蒲公英或者fir.im来生成二维码,这两个都是内测平台,我体验过蒲公英,需要将文件传到蒲公英网站然后他们生成二维码返回,传到别处总感觉怪怪的,于是我决定自己生成二维码然后放在下载地址的文件夹中,通过链接显示。
首先要在电脑上安装python环境,请看http://www.cnblogs.com/yuanzm/p/4089856.html(Python问题一)python 安装PIL (Python Imaging Library )来进行安装,如果已经安装继续往下看。生成二维码我用了qrcode这个库,感谢大神的分享,这个库如何使用就不介绍了,我只说一下Jenkins如何执行python。
添加python的环境变量到Jenkins的环境变量中,文章前面有提到过,在系统管理->系统设置中,如图添加python环境变量:

python.png

注意:键名需要和电脑上系统环境变量内的键名保持一致。
然后打开项目配置页面,在构建版块点击添加构建步骤,如图:

add_build.png

在编辑框内输入qrcode项目的使用命令

python_build.png

注意:下载地址需要自己拼接,生成路径也需要自己拼接。
这样每次打包后都会在生成apk的文件夹内生成一个对应的二维码。扫一扫就可以下载啦~~~
6.构建后操作
构建完成后,我希望将下载地址和二维码放在Build History的版块中,方便下载,那么我们就来设置一下,打开项目配置页,如图操作:

build_after.png

Description输入框内添加


<a href="http://192.168.1.88:8088/downloadApk/${BUILD_TIME}/AutoBuildTest-v${APP_VERSION}-${PRODUCT_FLAVOR}-${BUILD_TYPE}.apk">下载连接</a>

7.邮件通知
打完包,我想通知需要下载的人怎么办?发邮件~~Jenkins自带了邮件功能,但是不太好用,所以我选择了Email Extension Plugin这个插件来实现发邮件功能(已经在插件列表中)。进入系统管理->系统设置页面,如图:


mail.png

邮件格式:
[Jenkins构建通知]$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!(邮件由Jenkins自动发出,请勿回复~)
项目名称:$PROJECT_NAME
构建编号:$BUILD_NUMBER
构建状态:$BUILD_STATUS
触发原因:${CAUSE}
构建地址:<A HREF="${BUILD_URL}">${BUILD_URL}</A>
构建输出日志:<a href="http://192.168.1.201:8090/job/${PROJECT_NAME}/${BUILD_NUMBER}/console">http://192.168.1.201:8090/job/${PROJECT_NAME}/${BUILD_NUMBER}/console</a>
下载地址:<a href="http://192.168.1.88:8088/downloadApk">http://192.168.1.88:8088/downloadApk</a>

二维码下载:


最近修改:
${CHANGES, showPaths=false, format="%a:"%m"
", pathFormat="\n\t- %p"}

最终的效果图是介个样子的:


mail1.png

推荐阅读更多精彩内容