一步一步构建iOS持续集成:Jenkins+GitLab+蒲公英+FTP

一步一步构建iOS持续集成:Jenkins+GitLab+蒲公英+FTP

什么是持续集成
持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

为什么使用持续集成
1.减少风险2.减少重复过程3.任何时间、任何地点生成可部署的软件4.增强项目的可见性

常用的持续集成工具
Jenkins CI
Travis CI
Hudson CI
Circle CI

市面上的持续集成工具有很多,考虑到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-8import timeimport urllib2import timeimport jsonimport mimetypesimport osimport smtplibfrom email.MIMEText import MIMETextfrom email.MIMEMultipart import MIMEMultipartimport json#蒲公英应用上传地址url = 'http://www.pgyer.com/apiv1/app/upload'#蒲公英提供的 用户KeyuKey = 'xxxx'#上传文件的文件名(这个可随便取,但一定要以 ipa 结尾)file_name = 'xxxx.ipa'#蒲公英提供的 API Key_api_key = 'xxxxx'#安装应用时需要输入的密码,这个可不填installPassword = '123456'# 运行时环境变量字典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_pathelif 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() * 1000))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 0: 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,和pwdmail_host = 'smtp.xxx.com'mail_user = 'xxx@xxx.com'mail_pwd = '123'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 = environsStringbody = MIMEText(message, _subtype='html', _charset='utf-8')msg.attach(body)msg['To'] = mail_tomsg['from'] = mail_usermsg['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': '2',}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())

** 推荐拓展阅读

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容