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/LaunchDaemaons/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/LaunchDaemaons/org.jenkins-ci.plist: No such file or directory
这样的报错信息,但你用Finder打开路径是有这个文件的,然后你copy文件的路径发现就是这个路径,此时你再去执行
$ sudo launchctl unload /Library/LaunchDaemaons/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
,那么应该是如下的显示界面。

红色的路径就是让我们找到密码的路径,如果是通过命令行输入后浏览器打开地址,那么红色的提示路径就会是/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
欢迎大家提出更好的改进意见和建议,从搬砖到设计建筑的路上,你我同行!