测试基础 使用 Jenkins 搭建 iOS/Android 持续集成打包平台 (开箱即用)

debugtalk · 2016年06月28日 · 最后由 debugtalk 回复于 2017年06月28日 · 4908 次阅读
本帖已被设为精华帖!

背景描述

根据项目需求,现要在团队内部搭建一个统一的打包平台,实现对 iOS 和 Android 项目的打包。而且为了方便团队内部的测试包分发,希望在打包完成后能生成一个二维码,体验用户(产品、运营、测试等人员)通过手机扫描二维码后就能直接安装测试包。

该需求具有一定的普遍性,基本上所有开发 APP 的团队都可能会用到,因此我将整个需求实现的过程整理后形成此文,并且真正地做到了零基础上手,到手即飞、开箱即用,希望能对大家有所帮助。

首先,先给大家展示下平台建设完成后的整体效果:


该平台主要实现的功能有 3 点:

  • 定期对 GitHub 仓库进行检测,若有更新则自动执行构建打包;
  • 构建成功后根据 ipa/apk 生成二维码,并可在历史构建列表中展示各个版本的二维码,通过手机扫描二维码可直接安装对应版本;
  • 在构建结果页面中展示当次构建的成果物(Artifact,如.ipa.app.apkinfo.plist等文件),供有需要的用户进行下载。

接下来,本文就开始对平台建设的完整实现过程进行详细介绍。

安装 Jenkins

Jenkins 依赖于 Java 运行环境,因此需要首先安装Java

安装 Jenkins 的方式有多种,可以运行对应系统类型的安装包,可以通过 docker 获取镜像,也可以直接运行war包。

我个人倾向于直接运行war包的形式,只需下载jenkins.war后,运行如下命令即可启动 Jenkins。

$ nohup java -jar jenkins_located_path/jenkins.war --httpPort=88 &

如果不指定httpPort,Jenkins 的默认端口为 8080。

Jenkins 插件

Jenkins 有非常多的插件,可以实现各种功能的扩展。

针对搭建的 iOS/Android 持续集成打包平台,我使用到了如下几个插件。

  • GIT plugin
  • SSH Credentials Plugin
  • Git Changelog Plugin: 获取仓库提交的 commit log
  • build-name-setter:用于修改 Build 名称
  • description setter plugin:用于在修改 Build 描述信息,在描述信息中增加显示 QRCode(二维码)
  • Post-Build Script Plug-in:在编译完成后通过执行脚本实现一些额外功能
  • Xcode integration: iOS 专用(可选)
  • Gradle plugin: Android 专用(可选)

安装方式也比较简单,直接在 Jenkins 的插件管理页面搜索上述插件,点击安装即可。

创建项目(Job)

在 Jenkins 中,构建项目以 Job 的形式存在,因此需要针对每个项目创建一个 Job。有时候,一个项目中可能有多个分支同时在进行开发,为了分别进行构建,也可以针对每个分支创建一个 Job。

创建 Job 的方式有多种,本次只需要创建Freestyle project类型的即可。

Main page -> New Item -> Freestyle project

对于一个持续集成打包平台,每次打包都由 4 步组成:触发构建、拉取代码、执行构建、构建后处理。对应的,在每个 Job 中也对应了这几项的配置。

配置 Git 代码仓库

要对项目进行构建,配置项目的代码仓库是必不可少的。由于当前我们的项目托管在 GitHub 私有仓库中,因此在此需要对Git进行配置。

【Source Code Management】配置栏目下,如果之前GIT plugin安装成功,则会出现Git选项。

配置 Git 代码仓库时,有三项是必须配置的:仓库 URL 地址(Repository URL)、仓库权限校验方式(Credentials),以及当前 Job 需要构建的代码分支(Branches to build)。

在配置Repository URL时,选择HTTPS URLSSH URL均可。不过需要注意的是,Credentials要和Repository URL对应,也就是说:

  • 如果Repository URLHTTPS URL形式的,那么Credentials就要采用 GitHub 用户名密码的校验方式;而且,如果在 GitHub 中开启了2FA(two-factor authentication),那么还需要在 GitHub 中创建一个Personal access token,输入密码时将这个Personal access token作为密码进行输入。
  • 如果Repository URLSSH URL形式的,那么就需要先在 Jenkins 所在的服务器上创建一个SSH秘钥对,并将公钥添加到 GitHub 的SSH keys中,然后在填写Credentials时,选择SSH Username with private key的校验方式,填入 GitHub Username、SSH 私钥、以及创建SSH秘钥对时设置的Passphrase

如果对 Git 权限校验的概念还比较模糊,可以参考《深入浅出 Git 权限校验》。

在配置Branches to build时,可以采用多种形式,包括分支名称(branchName)、tagNamecommitId等。其中分支名称的形式用的最多,例如,若是构建master分支,则填写refs/heads/master,若是构建develop分支,则填写refs/heads/develop

除了以上关于 Git 的必填配置项,有时根据项目的实际情况,可能还需要对 Jenkins 的默认配置项进行修改。

比较常见的一种情况就是对clone的配置进行修改。

在 Jenkins 的默认配置中,clone代码时会拉取所有历史版本的代码,而且默认的超时时限只有 10 分钟。这就造成在某些项目中,由于代码量本身就比较大,历史版本也比较多,再加上网络环境不是特别好,Jenkins 根本没法在 10 分钟之内拉取完所有代码,超时后任务就会被自动终止了(错误状态码 143)。

这种问题的解决方式也很简单,无非就是两种思路,要么少拉取点代码(不获取历史版本),要么提高超时时限。对应的配置在Advanced clone behaviours中:

  • Shallow clone:勾选后不获取历史版本;
  • Timeout (in minutes) for clone and fetch operation:配置后覆盖默认的超时时限。

配置构建触发器

代码仓库配置好了,意味着 Jenkins 具有了访问 GitHub 代码仓库的权限,可以成功地拉取代码。

那 Jenkins 什么时候执行构建呢?

这就需要配置构建触发策略,即构建触发器,配置项位于【Build Triggers】栏目。

触发器支持多种类型,常用的有:

  • 定期进行构建(Build periodically)
  • 根据提交进行构建(Build when a change is pushed to GitHub)
  • 定期检测代码更新,如有更新则进行构建(Poll SCM)

构建触发器的选择为复合选项,若选择多种类型,则任一类型满足构建条件时就会执行构建工作。如果所有类型都不选择,则该Jenkins Job不执行自动构建,但可通过手动点击【Build Now】触发构建。

关于定时器(Schedule)的格式,简述如下:

MINUTE HOUR DOM MONTH DOW

  • MINUTE: Minutes within the hour (0-59)
  • HOUR: The hour of the day (0-23)
  • DOM: The day of the month (1-31)
  • MONTH: The month (1-12)
  • DOW: The day of the week (0-7) where 0 and 7 are Sunday.

通常情况下需要指定多个值,这时可以采用如下 operator(优先级从上到下):

  • *适配所有有效的值,若不指定某一项,则以*占位;
  • M-N适配值域范围,例如 7-9 代表 7/8/9 均满足;
  • M-N/X*/X:以 X 作为间隔;
  • A,B,C:枚举多个值。

另外,为了避免多个任务在同一时刻同时触发构建,在指定时间段时可以配合使用H字符。添加H字符后,Jenkins 会在指定时间段内随机选择一个时间点作为起始时刻,然后加上设定的时间间隔,计算得到后续的时间点。直到下一个周期时,Jenkins 又会重新随机选择一个时间点作为起始时刻,依次类推。

为了便于理解,列举几个示例:

  • H/15 * * * *:代表每隔 15 分钟,并且开始时间不确定,这个小时可能是:07,:22,:37,:52,下一个小时就可能是:03,:18,:33,:48
  • H(0-29)/10 * * * *:代表前半小时内每隔 10 分钟,并且开始时间不确定,这个小时可能是:04,:14,:24,下一个小时就可能是:09,:19,:29
  • H 23 * * 1-5:工作日每晚 23:00 至 23:59 之间的某一时刻;

配置构建方式

触发策略配置好之后,Jenkins 就会按照设定的策略自动执行构建。但如何执行构建操作,这还需要我们通过配置构建方式来进行设定。

常用的构建方式是根据构建对象的具体类型,安装对应的插件,然后采用相应的构建方式。例如,若是构建Android应用,安装Gradle plugin之后,就可以选择Invoke Gradle script,然后采用Gradle进行构建;若是构建iOS应用,安装Xcode integration插件之后,就可以选择Xcode,然后选择Xcode进行构建。

该种方式的优势是操作简单,UI 可视化,在场景不复杂的情况下可以快速满足需求。不过缺点就是依赖于插件已有的功能,如果场景较复杂时可能单个插件还无法满足需求,需要再安装其它插件。而且,有些插件可能还存在一些问题,例如对某些操作系统版本或 XCode 版本兼容不佳,出现问题时我们就会比较被动。

我个人更倾向于另外一种方式,就是自己编写打包脚本,在脚本中自定义实现所有的构建功能,然后在Execute Shell中执行。这种方式的灵活度更高,各种场景的构建需求都能满足,出现问题后也能自行快速修复。

另外,对于 iOS 应用的构建,还有一个需要额外关注的点,就是开发者证书的配置。

如果是采用Xcode integration插件进行构建,配置会比较复杂,需要在 Jenkins 中导入开发证书,并填写多个配置项。不过,如果是采用打包脚本进行构建的话,情况就会简单许多。只要在 Jenkins 所运行的计算机中安装好开发者证书,打包命令在 Shell 中能正常工作,那么在 Jenkins 中执行打包脚本也不会有什么问题。

构建后处理

完成构建后,生成的编译成果物(ipa/apk)会位于指定的目录中。但是,如果要直接在手机中安装ipa/apk文件还比较麻烦,不仅在分发测试包时需要将好几十兆的安装包进行传送,体验用户在安装时也还需要通过数据线将手机与计算机进行连接,然后再使用 PP 助手或豌豆荚等工具进行安装。

当前比较优雅的一种方式是借助蒲公英(pgyer)fir.im等平台,将ipa/apk文件上传至平台后由平台生成二维码,然后只需要对二维码链接进行分发,体验用户通过手机扫描二维码后即可实现快速安装,效率得到了极大的提升。

上传安装包文件,生成二维码

不管是蒲公英还是fir.im,都有对应的 Jenkins 插件,安装插件后可以在Post-build中实现对安装包的上传。

除了使用 Jenkins 插件,fir.im还支持命令上传的方式,蒲公英还支持HTTP Post接口上传的方式。

我个人推荐采用命令或接口上传的方法,并在构建脚本中进行调用。灵活是一方面,更大的好处是如果上传失败后还能进行重试,这在网络环境不是很稳定的情况下极其必要。

Jenkins 成功完成安装包上传后,pgyer/fir.im平台会生成一个二维码图片,并在响应中将图片的 URL 链接地址进行返回。

展示二维码图片

二维码图片的 URL 链接有了,那要怎样才能将二维码图片展示在 Jenkins 项目的历史构建列表中呢?

这里需要用到另外一个插件,description setter plugin。安装该插件后,在【Post-build Actions】栏目中会多出description setter功能,可以实现构建完成后设置当次 build 的描述信息。这个描述信息不仅会显示在 build 页面中,同时也会显示在历史构建列表中。

有了这个前提,要将二维码图片展示在历史构建列表中貌似就可以实现了,能直观想到的方式就是采用HTMLimg标签,将<img src='qr_code_url'>写入到 build 描述信息中。

这个方法的思路是正确的,不过这么做以后并不会实现我们预期的效果。

这是因为 Jenkins 出于安全的考虑,所有描述信息的Markup Formatter默认都是采用Plain text模式,在这种模式下是不会对 build 描述信息中的 HTML 编码进行解析的。

要改变也很容易,Manage Jenkins -> Configure Global Security,将Markup Formatter的设置更改为Safe HTML即可。

更改配置后,我们就可以在 build 描述信息中采用HTMLimg标签插入图片了。

另外还需要补充一个点。如果是使用蒲公英(pyger)平台,会发现每次上传安装包后返回的二维码图片是一个短链接,神奇的是这个短连接居然是固定的(对同一个账号而言)。这个短连接总是指向最近生成的二维码图片,但是对于二维码图片的唯一 URL 地址,平台并没有在响应中进行返回。在这种情况下,我们每次构建完成后保存二维码图片的 URL 链接就没有意义了。

应对的做法是,每次上传完安装包后,通过返回的二维码图片短链接将二维码图片下载并保存到本地,然后在 build 描述信息中引用该图片的 Jenkins 地址即可。

收集编译成果物(Artifacts)

每次完成构建后,编译生成的文件较多,但是并不是所有的文件都是我们需要的。

通常情况下,我们可能只需要其中的部分文件,例如.ipa/.app/.plist/.apk等,这时我们可以将这部分文件单独收集起来,并在构建页面中展示出来,以便在需要时进行下载。

要实现这样一个功能,需要在【Post-build Actions】栏目中新增Archive the artifacts,然后在Files to archive中通过正则表达式指定成果物文件的路径。

设置完毕后,每次构建完成后,Jenkins 会在Console Output中采用设定的正则表达式进行搜索匹配,如果能成功匹配到文件,则会将文件收集起来。

总结

本文主要是对如何使用 Jenkins 搭建 iOS/Android 持续集成打包平台的基础概念和实施流程进行了介绍。对于其中涉及到的执行命令、构建脚本(build.py),以及 Jenkins 的详细配置,出于篇幅长度和阅读体验的考虑,并没有在文中进行详细展开。

为了实现真正的开箱即用,我将 Jenkins 的配置文件和构建脚本抽离出来形成一套模板,只需要导入到 Jenkins 中,然后针对具体的项目修改少量配置信息,即可将这一套持续集成打包平台运行起来,实现和文章开头插图中完全相同的功能效果。

详细内容请阅读《关于持续集成打包平台的 Jenkins 配置和构建脚本实现细节》

Read More ...

微信公众号:DebugTalk
原文链接:http://debugtalk.com/post/iOS-Android-Packing-with-Jenkins
构建脚本&配置文件:https://github.com/debugtalk/JenkinsTemplateForApp

在微信公众号 debugtalk 中发送Jenkins模板,获得相关资源信息。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 95 条回复 时间 点赞
tttttttttggggg 回复

陈年老帖也能被你翻出来😅

大大研究的好深入

Post-Build Script Plug-in 已经废弃了

各位大神,求问个问题:iOS 打正式包之前,需要先 debug 生成一个 bundle 资源包,然后才能打正式包,这种情况命令行怎么实现?

#92 楼 @debugtalk 我想要这样的效果

问下,上面一下问答说是在 Markup Formatter 中有 Raw HTML 这个选项。但我怎么都调不出。知道怎么弄吗?

#91 楼 @springs412 其实当前的配置就是不在构建列表里面显示二维码的 https://github.com/debugtalk/JenkinsTemplateForApp/

#90 楼 @debugtalk
怎么配置啊?能不能告之下

#88 楼 @springs412 可以的,稍微调整下配置就好了

不错,准备试试

能不能去除构建列表下面的二维码显示,只要构建的详细内容里显示

#86 楼 @jeff1001 我的是 1.9.5,其他版本没试过

#85 楼 @HuiTaiLang 你的 git 版本是多少呢?我的 2.7.2

#82 楼 @jeff1001 换一个低版本的 git 试一下,我之前用最新版本的 git 也是总拉不到代码。后来换了一个旧版本的 git 就好了。

#82 楼 @jeff1001 代码仓库没配置好吧,都没有成功拉取到代码

#76 楼 @diao2007 看一下你的 console 输出,二维码地址是多少,你应该是 Jenkins 服务的地址错了

#81 楼 @debugtalk 哦哦,谢谢楼上,不过运行的时候报,这个是怎么回事呢?

#80 楼 @jeff1001 这就是模板内容,可以直接用的

导入配置文件出现这个,不知道需要修改些什么呢?

#78 楼 @debugtalk 改了,现在已经解决,发现用 jenkins 的网络地址就可以了

#76 楼 @diao2007 有将 Markup Formatter 的设置更改为 Safe HTML 么?

#74 楼 @debugtalk 实际 ${WORKSPACE}/image/MiFit.png 是有图片的

#74 楼 @debugtalk 请教一个问题,就是Install Online,这里 img 后面的 src 地址,最后二维码不能在 jenkins 执行页面显示?如图所示:

#73 楼 @diao2007 没有现成的命令,一般都是通过脚本来修改配置文件。在我的工程项目中,就有修改版本号,和你这个比较类似,可以参考下。

请教一个问题,我在把代码 pull 下来之后,需要更改代码中的 bundleid 有没有办法通过命令行实现,更改 bundleid 呢?

#71 楼 @yefan 对啊,打包脚本的核心命令就那几个,只是需要实现更好的调用而已

#69 楼 @debugtalk android 部分有需要脚本的么,执行触发 gradle 构建不就好了么?

#68 楼 @jasonzhang328 目前是的,Android 部分还没加进去

#67 楼 @debugtalk 哦哦,知道了,多谢!另外多问下,build.py 只能构建 ios 的吗?我大概看了下脚本,感觉都是 ios 相关的;

#65 楼 @jasonzhang328 这个是配置 iOS 开发者证书的

PROVISIONING_PROFILE 的配置是配置哪里的账号?

PROVISIONING_PROFILE 是什么?

#61 楼 @skyseraph 地址无效了

#59 楼 @margna 选这个就行了

#11 楼 @simple 我的 security 设置里面也是只有 RAW HTML,这个该怎么处理

急求!!!详细内容请阅读《关于持续集成打包平台的 Jenkins 配置和构建脚本实现细节》。就差最后一步啦大神

新手学习

陈恒捷 [该话题已被删除] 中提及了此贴 07月19日 10:27

不错,之前只是 android 用过持续集成

#53 楼 @alisa_yi 不是,是用来生成二维码图片的,参数就是穿进去一个地址,然后就能给一个图片出来,不论是 apk 地址还是 ipa 地址

#52 楼 @simple 你给的这个是不是 for 安卓,不是 ios 啊~ 怎么用呢,我是小白

#51 楼 @alisa_yi 本地生成,用我上面给的 jar 包就能生成一个本地的二维码图片,然后就可以让 jenkins 去用了

@
#11 楼 @simple
编译都是在公司内网环境下,生成的 apk 没法上传到外网 fir.m,这个怎么解决呀,怎么生成二维码给我扫描下载

#49 楼 @snowmaster ipa,直接可以安装

iOS 扫描二维码只是下载 ota 文件?还是直接就是安装?

#45 楼 @gaomengsuijia 差别只在于代码配置那儿,其它的都一样

赞,超级不错,借鉴了。

好文,这里也用的这一套,不过没有二维码这个,收藏了

代码管理是用 svn 的,咋弄?

#43 楼 @jira 好吧,我们的 apk 提测的时候不用加固,只要混淆就行

#42 楼 @simple 也是本地,但是要在第三方平台加固

#41 楼 @jira 没明白你的意思,apk 放在 jenkins 的 job workspace 下面就可以吧?你部署 jenkins 难道是放云端的?

#33 楼 @simple 我这边试了下 可以的,但是哈,必须要有个本地服务器管理才行么,要不然生成的 apk 还是得挂在第三方平台

#37 楼 @mmk1992 其实我们上传 apk/ipa 到蒲公英,蒲公英已经帮我们生成了二维码地址,扫描那个二维码 也是可以滴

集成二维码下载功能,工作效率提高不少,值得借鉴

后续试用下

最近正在用,顶一个

64楼 已删除

#33 楼 @simple good,我拉下来看看

#30 楼 @jira https://github.com/ariesliu/QRcode4JAVA 项目地址,你下载下来打包就行,代码很简单,基于谷歌 zxing 项目,你可以自己定制

#29 楼 @debugtalk 我升级到了 2.12,死活看不到这个入口,这个是需要配置什么吗

#29 楼 @simple 共享一下吧 我需要 谢谢哈~~

我写了一个简单的,本地放一个 jar 包,传两个参数就能生成图片二维码,有需要的话我发个 github 地址

—— 来自 TesterHome 官方 安卓客户端

#24 楼 @allanwendy 这个应该是证书没有安装好,最好找研发人员帮你配制下

#25 楼 @allanwendy 我直接用的最新版的 Jenkins,对于低版本的没有试过

将 Markup Formatter 的设置更改为 Safe HTML 即可 @simple @debugtalk jenkins 2.0 没有这个设置入口,大家怎么解决的?

@debugtalk 我配置了 Provisioning Profile,为什么构建过程中,总提示无法匹配到呢?

#21 楼 @bocycn 上传到蒲公英,自动会生成二维码,不用 py 吧?

二维码生成还是已经实现好点

—— 来自 TesterHome 官方 安卓客户端

可以先把包编译到 archive 目录,用 python 生成本地 apk 包的 http 地址的二维码,手机扫描就会提示下载,再安装

#11 楼 @simple 问下哈 怎么在本地生成二维码?

@debugtalk 请问下 怎么实现命令 上传失败后重新上传?

其实我想弱弱的问下,LZ 说的配置文件自己做成了个模板,模板在哪里捏,可以下载直接使用么☺ 嘿嘿

#15 楼 @debugtalk 嗯,我用的是 1.651 的版本

#11 楼 @simple 感谢纠正;Jenkins 版本我用的是 2.10 的,不知道是不是 1.X 的没有这个功能

#10 楼 @luis 的确是,你那儿有做好的么?

#9 楼 @shenkai600 搞完后求分享😄

#8 楼 @dfan 很快就会发出来的,要是急着用,可以先看下 Jenkins 配置文件和构建源码:https://github.com/debugtalk/JenkinsTemplateForApp

在楼主的提示下完成了二维码的展示,遇到几个问题在这里标记一下:
1. 应该写为
2.多数持续集成环境都是内网环境,无法上传文件到外网服务器,另外 build 出来的 apk 在未进行保密措施之前是不允许这样做的,建议大家本地生成二维码
3.不知道是不是我的 jenkins 版本问题,security 设置里面是 RAW HTML,没有 SAFE HTML 这个选项,大家可以参考一下

弄完了发现手机扫内网地址不能访问,容我出去哭一会😂

是需要上传 app 到蒲公英或者 fir.im 生成二维码啊?这个最好自己实现为好。

二维码下载不错😍 ,我得去搞个本地环境生成 url

期待楼主<<关于持续集成打包平台的 Jenkins 配置和构建脚本实现细节>>更详细的介绍,谢谢!😃

上周搭建了一套,话说这个二维码下载的功能很不错,吸收了,谢谢楼主!😁

不错不错

—— 来自 TesterHome 官方 安卓客户端

想法好的很,很实用!

—— 来自 TesterHome 官方 安卓客户端

有点意思,下周搞搞

不错,公司程序员页搭建了这个让测试用这个打包

Monkey 将本帖设为了精华贴 06月28日 17:23

好高端

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册