一步一步构建iOS持续集成:Jenkins+GitLab+蒲公英+FTP
什么是持续集成
持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
为什么使用持续集成
1.减少风险
2.减少重复过程
3.任何时间、任何地点生成可部署的软件
4.增强项目的可见性
常用的持续集成工具
市面上的持续集成工具有很多,考虑到Jenkins的稳定性,我们还是选择以Jenkins来开始iOS的持续集成。
好吧,接下来就正式开始搭建iOS持续集成平台了。
Jenkins的安装
在Mac环境下,我们需要先安装JDK,然后在Jenkins的官网下载最新的war包。
下载完成后,打开终端,进入到war包所在目录,执行以下命令:
java -jar jenkins.war --httpPort=8888
httpPort指的就是Jenkins所使用的http端口,这里指定8888,可根据具体情况来修改。待Jenkins启动后,在浏览器页面输入以下地址:
http://localhost:8888
这样就打开Jenkins管理页面了。
Jenkins的配置
安装GitLab插件
因为我们用的是GitLab来管理源代码,Jenkins本身并没有自带GitLab插件,所以我们需要依次选择 系统管理->管理插件,在“可选插件”中选中“GitLab Plugin”和“Gitlab Hook Plugin”这两项,然后安装。安装Xcode插件
同安装GitLab插件的步骤一样,我们依次选择系统管理->管理插件,在“可选插件”中选中“Xcode integration”安装。安装签名证书管理插件
iOS打包内测版时,需要发布证书及相关签名文件,因此这两个插件对于管理iOS证书非常方便。还是在系统管理->管理插件,在“可选插件”中选中“Credentials Plugin”和“Keychains and Provisioning Profiles Management”安装。安装FTP插件
在系统管理->管理插件,在“可选插件”中选中“Publish over FTP”安装。安装脚本插件
这个插件的功能主要是用于在build后执行相关脚本。在系统管理->管理插件,在“可选插件”中选中“Post-Build Script Plug-in”安装。
好了,插件安装完,可以正式开始自动化构建了!!!
自动化构建
在Jenkins中,所有的任务都是以“item”为单位的。接下来我们就新建一个iOS的项目来开始自动化构建。点击“新建”,输入item的名称,选择“构建一个自由风格的软件项目”,然后点击“OK”。

然后按下图设置构建信息,

源码管理:
这里用到的是GitLab,先需要配置SSH,我们可以在Jenkins的证书管理中添加SSH。在Jenkins管理页面,选择“Credentials”,然后选择“Global credentials (unrestricted)”,点击“Add Credentials”,如下图所示,我们填写自己的SSH信息,然后点击“Save”,这样就把SSH添加到Jenkins的全局域中去了。

接下来,我们再回到刚刚新建的任务中,在源码管理中,选择Git,按下图填好相关信息。PS:Credentials不需要选择。

构建触发器设置
因为此教程不涉及自动测试这块的流程,所以不需要设置触发器。(以后会有另外的自动测试教程^_^)
构建环境设置
iOS打包需要签名文件和证书,所以这部分我们勾选“Keychains and Code Signing Identities”和“Mobile Provisioning Profiles”。
这里我们又需要用到Jenkins的插件,在系统管理页面,选择“Keychains and Provisioning Profiles Management”。

进入Keychains and Provisioning Profiles Management页面,点击“浏览”按钮,分别上传自己的keychain和证书。
上传成功后,我们再为keychain指明签名文件的名称。点击“Add Code Signing Identity”,最后添加成功后如下图所示:

这样我们的Adhoc证书和签名文件就已经在Jenkins中配置好了,接下来我们只需要在item设置中指定相关文件即可。
回到我们新建的item,找到构建环境,按下图选好自己的相关证书和签名文件。

Xcode配置
点击“增加构建步骤”,选择“Xcode”。
依次按下图填写项目信息:



脚本设置
我们没有勾选“Pack application and build.ipa”的原因是,Jenkins的Xcode插件不支持Mac10.10以上的打包了。所以,我们需要用脚本来自己实现iOS打包。
仍然是点击“增加构建步骤”,选择“Execute Shell”。
输入下列脚本:if [ -d "${WORKSPACE}/builds" ]; then rm -rf ${WORKSPACE}/builds; fi;
mkdir ${WORKSPACE}/builds;
if [ -d "${WORKSPACE}/builds/${BUILD_NUMBER}" ]; then rm -rf ${WORKSPACE}/builds/${BUILD_NUMBER}; fi;
mkdir ${WORKSPACE}/builds/${BUILD_NUMBER};
xcodebuild -project ${WORKSPACE}/testForiOS/testForiOS.xcodeproj -scheme "testForiOS" -sdk iphoneos archive -archivePath ${WORKSPACE}/builds/${BUILD_NUMBER}/archive CODE_SIGN_IDENTITY="iPhone Distribution: xxxxxxx"
xcodebuild -exportArchive -exportFormat IPA -archivePath ${WORKSPACE}/builds/${BUILD_NUMBER}/archive.xcarchive -exportPath ${WORKSPACE}/builds/${BUILD_NUMBER}/${JOB_NAME}_${BUILD_NUMBER}.ipa -exportProvisioningProfile "XC Ad Hoc: com.xxxxx.xxx"
这样我们就简单的实现了自动打包的所有配置了。
不过,当iOS应用打包好后,我们还想发给其他相关人员安装,包括公司内部的,外网的,都需要。这时我们还需配置OTA服务和内网FTP。
外网安装App我们需要用到现在市面上比较流行的免费平台,蒲公英。在上面蒲公英官网设置相关信息后,我们可以写一个简单的脚本,来实现App打包后,上传到蒲公英和公司内网以及邮件提醒相关人员这一系列操作。
我们先用Jenkins的插件配置FTP信息。进入系统管理页面,选择系统设置,找到“Publish over FTP”,按下图填好相关信息:

回到任务配置页面,点击“增加构建后操作步骤”,然后选择“Send build artifacts over FTP”,填写:

这样FTP服务就配置好了。
接下来我们再点击“增加构建后操作步骤”,选择“Execute a set of scripts”,如下图所示:

所以配置都已经设置好,点击“保存”,好了,我们可以试试点击“立即构建”按钮了。
SUCCESS!!!
以上就是iOS持续集成的简单内容,教程中暂未涉及到自动测试,以后会推出自动测试的内容,未完待续。。。。
附(脚本内容):
#coding=utf-
import time
import urllib2
import time
import json
import mimetypes
import os
import smtplib
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
import json #蒲公英应用上传地址
url = 'http://www.pgyer.com/apiv1/app/upload'
#蒲公英提供的 用户Key
uKey = 'xxxx'
#上传文件的文件名(这个可随便取,但一定要以 ipa 结尾)
file_name = 'xxxx.ipa'
#蒲公英提供的 API Key
_api_key = 'xxxxx'
#安装应用时需要输入的密码,这个可不填
installPassword = '' # 运行时环境变量字典
environsDict = os.environ
#此次 jenkins 构建版本号
jenkins_build_number = environsDict['BUILD_NUMBER'] #项目名称,用在拼接 tomcat 文件地址
project_name = 'xxxx'
#ipa 文件在 tomcat 服务器上的地址
ipa_file_tomcat_http_url = 'ftp://192.168.10.4/jenkins/iOS/' + jenkins_build_number + '/' + project_name +'_' + jenkins_build_number + '.ipa' #获取 ipa 文件路径
def get_ipa_file_path():
#工作目录下面的 ipa 文件
ipa_file_workspace_path = '/Users/Shared/Jenkins/Home/jobs/' + project_name + '/workspace/builds/' + jenkins_build_number + '/' + project_name + '_' + jenkins_build_number + '.ipa'
#tomcat 上的 ipa 文件
ipa_file_tomcat_path = '/usr/local/tomcat/webapps/' + project_name + '/static/' + jenkins_build_number + '/' + jenkins_build_number + '.ipa' if os.path.exists(ipa_file_workspace_path):
return ipa_file_workspace_path
elif os.path.exists(ipa_file_tomcat_path):
return ipa_file_tomcat_path #ipa 文件路径
ipa_file_path = get_ipa_file_path()
print ipa_file_path
#请求字典编码
def _encode_multipart(params_dict):
boundary = '----------%s' % hex(int(time.time() * ))
data = []
for k, v in params_dict.items():
data.append('--%s' % boundary)
if hasattr(v, 'read'):
filename = getattr(v, 'name', '')
content = v.read()
decoded_content = content.decode('ISO-8859-1')
data.append('Content-Disposition: form-data; name="%s"; filename="SASDKDemo.ipa"' % k)
data.append('Content-Type: application/octet-stream\r\n')
data.append(decoded_content)
else:
data.append('Content-Disposition: form-data; name="%s"\r\n' % k)
data.append(v if isinstance(v, str) else v.decode('utf-8'))
data.append('--%s--\r\n' % boundary)
return '\r\n'.join(data), boundary #处理蒲公英上传结果
def handle_resule(result):
json_result = json.loads(result)
if json_result['code'] is :
send_Email(json_result) #发送邮件
def send_Email(json_result):
appName = json_result['data']['appName']
appKey = json_result['data']['appKey']
appVersion = json_result['data']['appVersion']
appBuildVersion = json_result['data']['appBuildVersion']
appShortcutUrl = json_result['data']['appShortcutUrl']
#邮件接受者
mail_receivers = ['xxx@xxx.com', 'xxx@xxx.com']
#根据不同邮箱配置 host,user,和pwd
mail_host = 'smtp.xxx.com'
mail_user = 'xxx@xxx.com'
mail_pwd = ''
mail_to = ','.join(mail_receivers)
msg = MIMEMultipart() environsString = '<h3>移动端iOS安装包</h3><p>'
environsString += '<p>内网ipa包下载地址 : ' + ipa_file_tomcat_http_url + '<p>'
environsString += '<p>外网在线安装 : ' + 'http://www.pgyer.com/' + str(appShortcutUrl) + '<p>'
environsString += '<li><a href="itms-services://?action=download-manifest&url=https://ssl.pgyer.com/app/plist/' + str(appKey) + '">手机直接安装</a></li>'
message = environsString
body = MIMEText(message, _subtype='html', _charset='utf-8')
msg.attach(body)
msg['To'] = mail_to
msg['from'] = mail_user
msg['subject'] = 'iOSxxx版本最新打包文件' try:
s = smtplib.SMTP()
s.connect(mail_host)
s.login(mail_user, mail_pwd) s.sendmail(mail_user, mail_receivers, msg.as_string())
s.close() print 'success'
except Exception, e:
print e
############################################################# #请求参数字典
params = {
'uKey': uKey,
'_api_key': _api_key,
'file': open(ipa_file_path, 'rb'),
'publishRange': '',
}
coded_params, boundary = _encode_multipart(params)
req = urllib2.Request(url, coded_params.encode('ISO-8859-1'))
req.add_header('Content-Type', 'multipart/form-data; boundary=%s' % boundary)
try:
resp = urllib2.urlopen(req)
body = resp.read().decode('utf-8')
handle_resule(body)
except urllib2.HTTPError as e:
print(e.fp.read())
一步一步构建iOS持续集成:Jenkins+GitLab+蒲公英+FTP的更多相关文章
- DevOps之持续集成Jenkins+Gitlab
一.什么是DevOps DevOps(英文Development(开发)和Operations(技术运营)的组合)是一组过程.方法与系统的统称,DevOps是一组最佳实践强调(开发.运维.测试)在应用 ...
- 持续集成 Jenkins +Gitlab + SSH 自动发布 HTML 代码
目录 一.整体流程 二.Jenkins 配置 2.1.首先安装插件 2.2.配置目标服务器 2.3.创建 job 2.4.配置 gitlab 触发 三.改进 一.整体流程 二.Jenkins 配置 2 ...
- iOS 持续集成
iOS 持续集成系列 - 开篇 前言 iOS 开发在经过这几年的野蛮生长之后,慢慢地趋于稳定.无论开发语言是 Objective-C 还是 Swift,工程类型是 Hybird 还是原生,开发思想是 ...
- 使用 Fastlane 实现 IOS 持续集成
简介 持续集成是个“一次配置长期受益”的工作.但很多小公司都没有.以前在做Windows开发配置感觉简单一些,这次配置iOS的,感觉步骤还挺多.整理出来,分享给大家,不正确的地方请及时指正. 本文主要 ...
- 使用VSTS/TFS搭建iOS持续集成环境
TFS 自2015版开始支持跨平台的持续集成环境,通过提供开源的build agent为 Windows / linux / macOS 提供了统一的持续集成环境管理能力.这篇文章给大家介绍一下如何使 ...
- CI Weekly #21 | iOS 持续集成快速入门指南
搭建 iOS 持续集成环境要多久?每个 iOSer 都有不同的答案.这次我们整理了 flow.ci 的 iOS 持续集成的相关文档和最佳实践,希望帮你更快地完成构建.更新文档见: flow.ci iO ...
- 视频云SDK iOS持续集成项目实践
1. 前言 2016年, 我们维护的 iOS推流播放融合SDK KSYLive_iOS 在github上发布了40多个版本, 平均两周发布一个新版本, 经历了最初痛苦的全手动版本构建和维护, 到后来慢 ...
- 使用Jenkins+Calabash+Cocoapods搭建iOS持续集成环境
使用jenkins+calabash+cocoapods搭建ios持续集成环境 持续集成 持续集成到底是什么呢?依据敏捷大师Martin Fowler的定义: 持续集成是一种软件开发实践. 在持续集成 ...
- fir.im Weekly - 暖心的 iOS 持续集成,你值得拥有
一则利好消息,flow.ci 支持 iOS 项目持续集成,想试试的伙伴去 Gitter群 问问.首批尝鲜用户@阿米amoy 已经用 flow.ci 实现了基本的 iOS 持续集成,并详细记录整个 Bu ...
随机推荐
- 洛谷P3293 [SCOI2016]美味(主席树)
传送门 据说这题做法叫做可持久化trie树?(然而我并不会) 首先考虑一下贪心,从高位到低位枚举,如果能选1肯定比选0优 假设已经处理到了$b$的第$i$位,为1(为0的话同理就不说了) 那么只有当$ ...
- IT兄弟连 JavaWeb教程 使用AJAX发送POST请求并获取响应
POST请求用于向服务器发送应该被保存的数据,因此POST请求天然比GET请求多需要一份需要被保存的数据.那么这些数据应该放在何处呢?毕竟,我们的open()方法接收的三个参数都没有合适的位置. 答案 ...
- jconsole 本地连接失败
http://limaoyuan.iteye.com/blog/1541745 加jvm 启动参数即可: -Dcom.sun.management.jmxremote -Dcom.sun.manag ...
- CF1141F Same Sum Blocks(easy/hard)
传送门easy 传送门hard 切水题的感觉真好 看到数据范围这么小,所以暴力枚举所有的可能,然后用map+vector存下每种值的区间,然后贪心去选 代码: #include<cstdio&g ...
- Sass 愿景
在最近的一个 CSS 见面会上,我向与会者提问,“有人会在日常的工作流中使用 Sass 吗?”回答结果压倒性的表示肯定——保守谨慎地使用 Sass 已经成为过去式.Sass 正迅速成长为编写 CSS ...
- [HNOI2010] 弾飞绵羊
题目链接: 传送门 题目分析: 题外话: 我即使是死了,钉在棺材里了,也要在墓里,用这腐朽的声带喊出: 根号算法牛逼!!! 显然,这是一道LCT裸题,然而在下并不会LCT于是采用了分块瞎搞 对于每个点 ...
- NETCORE MVC模块化
NETCORE MVC模块化 ASP.NETCORE MVC模块化编程 前言 记得上一篇博客中跟大家分享的是基于ASP.NETMVC5,实际也就是基于NETFRAMEWORK平台实现的这么一个轻量级插 ...
- mysql 驱动问题
转 : https://blog.csdn.net/bloodycuckoo/article/details/51175339 转 : https://blog.csdn.net/u010746431 ...
- Adobe CC Family (CC 2015) 大师版
Adobe CC Family (CC 2015) 大师版 v5.6#2 ###请彻底卸载旧版后再安装本版! 更新 Adobe Digital Publishing CC 2016.1更新 Adobe ...
- autofac 注入生命周期
创建实例方法 1.InstancePerDependency 对每一个依赖或每一次调用创建一个新的唯一的实例.这也是默认的创建实例的方式. 官方文档解释:Configure the component ...