iOS开发-自动化打包Jenkins集成

前言

自动化打包根本目的是为了节约时间,把重复且无技术含量的事情交给机器去做。Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。更多的介绍大家自行百度,这里就不啰嗦了。

由于工作需要,我们存在的自动打包的工程有3种,一种是单一的工程打包;一种是集成cocoapod的打包;还有一种是有www文件需要插入到工程里的打包方式,后边会一一讲到3种配置。

环境配置:
Mac OS 10.12.6
Xcode9.2

一、Jenkins安装

打开Jenkins官网下载最新的pkg安装包。安装完成之后,Safari可能会自动打开,如果没有自动打开,打开浏览器,输入http://localhost:8080

这时候可能出现这个页面,这个问题的原因就是Java环境有问题,需要重装Java环境。下载Java的JDK


一般会有2个版本可选,选一个下载即可,下载完安装后打开终端,cd进入到jenkins.war包所在目录,执行以下命令:
$ java -jar jenkins.war --httpPort=8080
httpPort指的就是Jenkins所使用的http端口,这里指定8080(默认的就是这个),可根据具体情况来修改。待Jenkins启动后,在浏览器页面输入以下地址:http://localhost:8080这样就可以打开Jenkins管理页面了。

接下来是我们遇到的第一个坑也是需要注意的地方。

一般来说浏览器直接打开http://localhost:8080并没什么不对,但是等你用Jenkins打包的时候你会发现有各种权限的报错问题。原因就是直接用浏览器打开创建账号,那么Jenkins的工作目录会建立在/Users/Shared/Jenkins下。具体过程参见 stackoverflow
正确的启动方式是:
$ sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
$ java -jar /Applications/Jenkins/jenkins.war --httpPort=8080
这时,Jenkies会在/Users/[user name]/.Jenkins 下面建立工作目录,从而它就有权限去获取相关的keychain。.Jenkins是一个隐藏文件,通过进入文件夹路径的方式查看或者显示隐藏文件查看。
$ defaults write com.apple.finder AppleShowAllFiles -bool true 此命令显示隐藏文件
$ defaults write com.apple.finder AppleShowAllFiles -bool false 此命令关闭显示隐藏文件
执行显示或隐藏命令后需要重新启动Finder即可执行。

此时你可能会遇到/Library/LaunchDaemons/org.jenkins-ci.plist: No such file or directory这样的报错信息,但你用Finder打开路径是有这个文件的,然后你copy文件的路径发现就是这个路径,此时你再去执行
$ sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
就会提示你deny permission,需要输入密码,这时就正常了。

输入$ java -jar /Applications/Jenkins/jenkins.war --httpPort=8080之后如果出现下边的信息就标识Jenkins已经启动了。

此时在浏览器输入http://localhost:8080即可。

注意:这种方式打开的Jenkins在自动化打包时,不能关闭运行Java环境的终端。

二、Jenkins账号设置

如果Jenkins安装完是用浏览器直接打开http://localhost:8080,那么应该是如下的显示界面。

1194012-c8468fd91737f725.png

红色的路径就是让我们找到密码的路径,如果是通过命令行输入后浏览器打开地址,那么红色的提示路径就会是/Users/[user name]/.Jenkins/.......就表明Jenkins在当前的登录账号下建立了工作目录,之后会省去很多麻烦。
按路径打开时发现secrets文件夹无权限访问,右键点击文件夹 -> 显示简介 -> 打开共享与权限 ,给everyone加上读与写权限,进入文件夹后可以看到名字为initialAdminPassword的文件。

这个文件夹也有权限问题,按上边的操作修改下权限即可,打开后可以拷贝里边的密码,然后在Jenkins页面上输入即可。

然后点击install suggested plugins ,即下载推荐插件。

到这就可以设置用户名和密码了。


三、安装插件及添加钥匙串和描述文件等准备

因为我们用的是GitLab来管理源代码,Jenkins本身并没有自带GitLab插件,所以我们需要依次选择 系统管理->管理插件,在“可选插件”中选中“GitLab Plugin”和“Gitlab Hook Plugin”这两项,然后安装。

如果你想用Xcode插件作为配置打包任务可以下载 xcode integration插件,下载方式也是系统管理->管理插件,在“可选插件”中搜索下载。不过我还是偏向与脚本的方式,因为脚本虽然麻烦些但是更加灵活。比如我们打包的命名方式,打完包的存放文件路径等都可以通过脚本做配置。

自动打包的job任务配置也需要添加钥匙串和描述文件,这时需要安装Keychains and Provisioning Profiles Management插件,安装后在Jenkins首页点击系统管理会找到这个插件,点击进去。


如图这里可以上传的文件时钥匙串和描述文件。不能直接上传证书文件。钥匙串的目录可以打开钥匙串点击登录钥匙串查看。

按图索骥,按显示的路径通过Finder直接打开文件夹。


然后拷贝一份安装有我们打包证书的钥匙串文件,即login.keychain-db。此时需要注意,上传到Jenkins的只认.keychain后缀和.mobileprovision后缀的文件,其他文件都会上传失败。所以我们要把这个上传的钥匙串后缀的-db去掉,文件名修改成login.keychain,然后再上传。

上传成功后Keychains下边会显示Filename为login.keychain,可以添加打包用的证书。

这个名字可以在钥匙串中点击查看。

接下来添加描述文件,先添加描述文件的导向路径,
/Users/[user name]/Library/MobileDevice/Provisioning Profiles
。描述文件和钥匙串一样的添加上传方式。添加后就可以看到描述文件信息了。

上传后点击 save 按钮保存就可以了。

四、创建配置单一工程任务

xcodebuild + xcrun命令
Xcode提供了一套构建打包的命令,就是xcodebuild和xcrun命令。xcodebuild把我们指定的任务打包成.app文件,xcrun将指定的.app文件转换为对应的.ipa文件。
xcodebuild官方文档xcrun官方文档

接下来创建任务,Jenkins首页点击新建。

如果我们已经创建了任务,并且其他配置都一样就改个证书什么的,可以下滑看到可以复制一份现有的任务,输入名字就可以选择。

新建任务打开后,因为我们是用SVN管理代码,所以选Subversion。



点击add添加SVN的账号和密码。

如果地址和账号密码都对,是这样的。


路径不对,或账号密码不对。

有两个自动化的配置比较重要:

Poll SCM (poll source code management) 轮询源码管理
需要设置源码的路径才能起到轮询的效果。一般设置为类似结果: 0/5 * * * * 每5分钟轮询一次
Build periodically (定时build)
一般设置为类似: 00 20 * * * 每天 20点执行定时build 。当然两者的设置都是一样可以通用的。

详细的可以点开介绍查看。

然后选择打包证书和描述文件。

添加脚本

# 工程名
TARGET_NAME="VideoEditDemo"

# 文件名前缀
APP_NAME="视频编辑"

# 证书
CODE_SIGN_DISTRIBUTION="iPhone Distribution: Smao Tech Co.,LTD."
# info.plist路径
project_infoplist_path="./${TARGET_NAME}/Info.plist"

#取版本号
bundleShortVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${project_infoplist_path}")

#取build值
bundleVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${project_infoplist_path}")

DATE="$(date +%Y%m%d)"
IPANAME="${APP_NAME}_V${bundleShortVersion}_${DATE}.ipa"

#要上传的ipa文件路径
IPA_PATH="$HOME/Desktop/MyWorkPlace/自动化打包IPAs/${IPANAME}"
echo ${IPA_PATH}
echo "${IPA_PATH}">> text.txt

#下面2行是没有Cocopods的用法
echo "=================clean================="
xcodebuild -target "${TARGET_NAME}"  -configuration 'Release' clean

echo "+++++++++++++++++build+++++++++++++++++"
xcodebuild -target "${TARGET_NAME}" -sdk iphoneos -configuration 'Release'  CODE_SIGN_IDENTITY="${CODE_SIGN_DISTRIBUTION}" SYMROOT='$(PWD)'


xcrun -sdk iphoneos PackageApplication "./Release-iphoneos/${TARGET_NAME}.app" -o ~/"Desktop/MyWorkPlace/自动化打包IPAs/${IPANAME}"

要上传的ipa文件路径是我创建了一个文件夹专门用来放自动打包的。

构建一次,各个颜色代表的意义如下:

天气的晴雨表代表了任务的质量,这也是Jenkins的一个特色。

如果构建失败了,可以去查看Console Output可以查看log日志。

到此,一个单一工程的自动化打包就配置好了。这时可以点应用 保存 ,然后点击构建,构建成功后可以点开存放ipa文件的文件夹找到对应的ipa安装包。

五、配置cocoapod任务

这里为了不重复,只说与单一工程不同的地方。cocoapod需要install安装依赖的三方库,所以这里需要在原有的构建脚本前边加一个脚本。(cocoapod自动化打包install安装三方库速度特别慢,还有可能中途下载时间太长失败,重新点构建再试一般就没问题了)

#bin/bsah - l

export LANG=en_US.UTF-8

export LANGUAGE=en_US.UTF-8

export LC_ALL=en_US.UTF-8

cd 【你的工程目录】

/usr/local/bin/pod install --verbose --no-repo-update

第二个脚本也需要有些修改

# 工程名
TARGET_NAME="MeetingProject"

# 文件名前缀
APP_NAME="会务产品"

# 证书
CODE_SIGN_DISTRIBUTION="iPhone Distribution: Smartdot Technologies Co.,LTD."
# info.plist路径
project_infoplist_path="./${TARGET_NAME}/Info.plist"

#取版本号
bundleShortVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${project_infoplist_path}")

#取build值
bundleVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${project_infoplist_path}")

DATE="$(date +%Y%m%d)"
IPANAME="${APP_NAME}_V${bundleShortVersion}_${DATE}.ipa"

#要上传的ipa文件路径
IPA_PATH="$HOME/Desktop/MyWorkPlace/自动化打包IPAs/${IPANAME}"
echo ${IPA_PATH}
echo "${IPA_PATH}">> text.txt


#下面2行是集成有Cocopods的用法
echo "=================clean================="
xcodebuild -workspace "${TARGET_NAME}.xcworkspace" -scheme "${TARGET_NAME}"  -configuration 'Release' clean

echo "+++++++++++++++++build+++++++++++++++++"
xcodebuild -workspace "${TARGET_NAME}.xcworkspace" -scheme "${TARGET_NAME}" -sdk iphoneos -configuration 'Release' CODE_SIGN_IDENTITY="${CODE_SIGN_DISTRIBUTION}" SYMROOT='$(PWD)'

xcrun -sdk iphoneos PackageApplication "./Release-iphoneos/${TARGET_NAME}.app" -o ~/"Desktop/MyWorkPlace/自动化打包IPAs/${IPANAME}"

此时你构建打包,应该会报这样的错

这是因为Jenkins没有安装cocoapod,打开用户偏好设置 -> 用户与群组。

正常这里不会有Jenkins这个名字,除非你设置过。这里是我已经给Jenkins设置过了,右键点击高级选项,把名字写上。

我们需要给Jenkins一个密码,如果之前没设置过密码,这里应该是更改密码,否则是重置密码。

为了可以快速切换登录账号,我们需要这样的勾选。


然后可以在这里快速切换登录用户,接下来就可以切换登录Jenkins账号,安装cocoapod环境了,安装完成后,cocoapod自动化打包就没什么问题了。

六、配置插入文件打包任务

添加SVN地址,这里因为我们SVN这个目录下的文件就为WWW,所以复制过来也要建立一个www文件夹放这些文件,否则这些文件就直接复制到工程目录一级目录下非常散乱。


有插入文件,自然需要在打包的时候插入进去,所以我们还需要在构建单一工程的脚本前加一段脚本。

#!/bin/bash

# Copyright by Galen (2014-2014)
# All rights reserved

APP=`find -L . -name *.app -type d`
echo "will cp source file to:"$APP"..."
#exit 1
\cp -aR $WORKSPACE/www "$APP"

# 删除隐藏文件
for X in `find -L "$APP" -name *.svn*`
do
rm -rf "$X"
done

七、上传蒲公英应用管理平台

我们既然要自动化就自动化到底,所以我们打出来的安装包应该自动上传到一个应用管理平台,这样别人就可以直接下载测试或使用。一般常用的是上传到蒲公英应用管理平台。

1.安装fir-clifir的命令行工具,需要先装好ruby再执行

gem install fir-cli

2.自动上传至蒲公英

#蒲公英上的User Key
uKey="9dba14768e*****8e7a606ea31e04"
#蒲公英上的API Key
apiKey="88127f49b2******e9536babe6920c10"
#要上传的ipa文件路径

#要上传的ipa文件路径
IPA_PATH=$(cat text.txt)

rm -rf text.txt

#执行上传至蒲公英的命令
echo "++++++++++++++上传蒲公英 上传中 +++++++++++++"
curl -F "file=@${IPA_PATH}" -F "uKey=${uKey}" -F "_api_key=${apiKey}" http://www.pgyer.com/apiv1/app/upload

八、过程中一些坑和小技巧

  • 1.Jenkins工作目录不在当前登录用户下的权限问题
    这个问题在最开始就说了,这里的报错只是其中的个别,还有其他提示的权限问题基本都是Jenkins工作目录引起的权限问题。当然,你可以点开对应的路径下的文件进行授权,但是这意味着路径上的每一个文件都需要这样的授权处理,并且报一次错就得来这么一轮,我们不可能这么操作。

所以工作目录的问题其实很重要。

报错:
Command /usr/bin/codesign failed with exit code 1 ** ARCHIVE FAILED **

  • 2.xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH

解决办法

  • 3.unknown error -1=ffffffffffffffff Command /bin/sh failed with exit code 1

这个错的问题可能有很多种,这里有几种原因和处理方式:
原因1
原因2

  • 4.error: exportArchive: "AppName.app" requires a provisioning profile with the Push Notifications and App Groups features.
    Error Domain=IDEProvisioningErrorDomain Code=9
    "AppName.app" requires a provisioning profile with the Push Notifications and App Groups features." UserInfo={NSLocalizedDescription="AppName.app" requires a provisioning profile with the Push Notifications and App Groups features., NSLocalizedRecoverySuggestion=Add a profile to the "provisioningProfiles" dictionary in your Export Options property list.}
    // 或
    "Error Domain=IDEProvisioningErrorDomain Code=9 ""ios-simple-objc.app" requires a provisioning profile."
    UserInfo={NSLocalizedDescription="ios-simple-objc.app" requires a provisioning profile., NSLocalizedRecoverySuggestion=Add a profile to the "provisioningProfiles" dictionary in your Export Options property list.}"
    解决方式

不过笔者目前的Xcode9.2没有遇到这个提示,是之前Jenkins工作目录不对的时候调试出现过,用脚本添加ExportOptions.plist文件也不好使,如果有类似的问题大家还是百度并尝试吧。

  • 4.修改端口
    如果要修改端口,比如7070,可在重启jenkins前执行以下命令修改端口参数:
    sudo defaults write /Library/Preferences/org.jenkins-ci httpPort 7070
    然后重启jenkins:
    sudo launchctl unload -w /Library/LaunchDaemons/org.jenkins-ci.plist
    sudo launchctl load -w /Library/LaunchDaemons/org.jenkins-ci.plist
    到此,可以访问http://localhost:7070了。

  • 5.Mac卸载Jenkins

//进入以下目录,双击运行
/Library/Application Support/Jenkins/Uninstall.command
//也可以这样运行
sh "/Library/Application Support/Jenkins/Uninstall.command"

//删除配置,这个可选
sudo rm -rf /var/root/.jenkins ~/.jenkins
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
sudo rm /Library/LaunchDaemons/org.jenkins-ci.plist
sudo rm -rf /Applications/Jenkins "/Library/Application Support/Jenkins" /Library/Documentation/Jenkins
sudo rm -rf /Users/Shared/Jenkins
sudo dscl . -delete /Users/jenkins
sudo dscl . -delete /Groups/jenkins
sudo rm -f /etc/newsyslog.d/jenkins.conf
pkgutil --pkgs | grep 'org\.jenkins-ci\.' | xargs -n 1 sudo pkgutil --forget

//如果使用brew安装的,可以执行以下命令
brew uninstall jenkins

参见

欢迎大家提出更好的改进意见和建议,从搬砖到设计建筑的路上,你我同行!

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

推荐阅读更多精彩内容