OC底层原理43.2:自动化打包(二)Jenkins + GitLab实现自动化打包

张建 lol

前言

一般大型的公司都有部署好的Jenkins环境,所以这里不再赘述Jenkins的搭建环境过程,对于Jenkins不了解的童鞋可以自行google下。

Jenkins作为可扩展的自动化服务器,可用作简单的持续集成(CI,Continuous Integration)服务器,或是持续交付(CD,Continuous Deployment)中心。其特点如下:

  • 即时性。Jenkins是一个基于Java运行的程序,可立即运行,包含Windows、MacOSX、Linux等。

  • 配置简单。可以通过网页轻松配置

  • 插件丰富。目前有1000多插件

  • 扩展性强,Jenkins可以通过插件架构进行扩展,从而为Jenkins提供了无限可能

  • 分布式部署,可以在多态机器上分配工作,帮助开发者快速构建、测试等

所以,对于开发者来说,Jenkins可以简单的通过配置git源和xcode插件配置打包项,就可以实现服务器自动打包了。

Jenkins实现自动打包的方式主要有两种:

  • 无Jenkins服务器: 搭建Jenkins服务器 + 配置环境 + 自动打包配置

  • 有Jenkins服务器: 创建Mac从节点 + 配置环境 + 自动打包配置

备注:以下配置的前提都是基于已部署好的Jenkins服务器进行的。

Jenkins环境配置

全局的配置主要是配置打包所需的证书和签名。使用管理员账户登录Jenkins,安装以下插件:

上传证书

  • 1、将发布证书+签名相关文件夹拷贝至桌面,并将 login.keychain-db 改为 login.keychain

  • 2、manage jenkins -> Keychains and Provisioning Profiles Management -> 选择login文件并upload

  • 3、填写正确的code signing,如下所示,红框中的内容就是code signing的值

最终效果如下:

上传签名

  • 1、填写 Provisioning Profiles 文件的具体路径,格式为:/Users/管理员用户名/Library/MobileDevice/Provisioning Profiles

  • 2、拷贝具体的签名,并upload,最终效果如下所示

Mac从节点创建

【前提】:Jenkins的master是Linux系统,首先尝试在Linux打包,但是结果不尽人意,主要有以下问题:
1、pod 命令找不到,使用npm,但是npm命令不会生成 .xcworkspace 文件
2、.xcodebuild 命令找不到,有文档提示使用Facebook提供的xcbuild,但是仍然报错

【结论】
iOS在Linux打包比较复杂,需要找到pod、xcode命令相关的替代命令,以及其他未发现的坑。
所以为了更好的将自动化应用起来,采用了jenkins配置MaxOSX从节点,用于解决pod、xcode命令找不到的问题。

创建Mac从节点的步骤如下:

  • 1、开启要绑定的MacOSX系统的电脑的远程登录:系统偏好设置☞共享☞勾选☞远程登录。用于获取远程登录的用户名 + IP

  • MacOSX 的user文件中创建 Jenkins 文件夹:/User/Shared/Jenkins,需要开放读写权限

3、管理员账户登录jenkins,创建从节点:Manage Jenkins ☞ Manage Node and Clouds ☞ New Node

其中Credentials的配置如下所示:add -> Jenkins -> 选择Username with password

  • 5、到此为止,节点创建完成了,会自动连接:MacOSX -> log查看连接日志,以便及时排查问题

创建iOS项目

1、新建项目:New Item,填写项目名称,选择项目风格

通用配置

2、【特别提醒!!!】在项目时,需要配置运行的节点:项目 -> configure -> General

源码配置

  • 3、配置源码 - Source Code Management

说明:

  • git源码链接:最好是SSH的链接,不要https的
  • 配置源码的分支,一般是master
  • redential:Add - Jenkins - SSH Username with private key,粘贴SSH

Item环境配置

4、配置编译环境 - Build Environment
配置keychain,选择对应的code signing(注:创建项目后,需要点击Apply,可能才会显示配置好的证书签名)

自动打包脚本配置
构建打包shell脚本,主要分为两部分:

  • git clone源码 + pod install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 使用方法
# 1、替换自己项目:项目文件夹名(同git名一致)、git地址
# 2、


# 使用cocoapods需要加入这句
#!/bin/bash -l
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8


# 项目的参数 build:表示是否进行编译
if [ $build == false ]; then
exit
fi

if [ -d "xxxxx" ]; then
echo '----------已有项目----------'
else
echo '----------下载项目----------'
# 需要替换成自己项目的地址
git clone git@xxxxx.git
fi

# 进入项目文件夹
cd xxxxx
echo 'pod install路径--'${workdir}
# 切换分支
git checkout dev
# 拉取最新代码 git pull origin 【远程分支名】:【本地分支名】
git pull origin dev:dev


# 更新pod
# 跳转至podfile所在目录
cd xxxxx
cur_dir=$(pwd)
echo '-----------install路径--'${cur_dir}
echo '---------------------------------------'
pod install
  • 打ipa包 + 上传AppStore
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#项目名
PROJECT_NAME='xxxxx'

#App名称
APP_NAME='xxxxx'

#scheme名称
SCHEME_NAME='xxxxx'

#打包模式
CONFIGURATION=release

# 下面两个参数只是在手动指定Pofile文件的时候用到,如果使用Xcode自动管理Profile,直接留空就好
# (跟method对应的)mobileprovision文件名,需要先双击安装.mobileprovision文件.手动管理Profile时必填
mobileprovision_name=""

# 项目的bundleID,手动管理Profile时必填
bundle_identifier=""

echo "--------------------脚本配置参数检查--------------------"
echo "PROJECT_NAME = ${PROJECT_NAME}"
echo "APP_NAME = ${APP_NAME}"
echo "SCHEME_NAME = ${SCHEME_NAME}"
echo "CONFIGURATION = ${CONFIGURATION}"
echo "mobileprovision_name = ${mobileprovision_name}"
echo "bundle_identifier = ${bundle_identifier}"


# 指定输出导出文件夹路径,version是项目配置的参数,每次可手动输入
export_path=${cur_dir}/build-${version}
#archive文件存放路径
ARCHIVE_PATH=$export_path/$SCHEME_NAME.xcarchive

#ipa文件存放路径
IPA_PATH=${export_path}/

#plist 文件路径:导出ipa所需的文件
EXPORT_OPTIONS_PLIST_PATH=${cur_dir}/ExportOptions.plist


echo "--------------------脚本固定路径检查--------------------"
echo "export_path = ${export_path}"
echo "ARCHIVE_PATH = ${ARCHIVE_PATH}"
echo "IPA_PATH = ${IPA_PATH}"
echo "EXPORT_OPTIONS_PLIST_PATH = ${EXPORT_OPTIONS_PLIST_PATH}"


# 先删除export_path文件
if [ -f "$export_path" ] ; then
echo "${export_path}文件存在,进行删除"
rm -f $export_path
fi



#清理工程
echo "--------------------正在清理工程--------------------"
xcodebuild clean -workspace ${PROJECT_NAME}.xcworkspace -scheme ${SCHEME_NAME}

echo "--------------------清理完成 🎉 🎉 🎉--------------------"

security unlock-keychain -p "1109221208l" ~/Library/Keychains/login.keychain

#生成archive文件
echo "--------------------正在生成 .xcarchive 文件--------------------"
xcodebuild \
-workspace ${PROJECT_NAME}.xcworkspace \
-scheme ${SCHEME_NAME} \
-configuration ${CONFIGURATION} \
-archivePath ${ARCHIVE_PATH} \
archive


# 检查是否构建成功
# xcarchive 实际是一个文件夹不是一个文件所以使用 -d 判断
if [ -d "$ARCHIVE_PATH" ] ; then
echo " 项目构建成功 🚀 🚀 🚀 "
else
echo " 项目构建失败 😢 😢 😢 "
exit 1
fi
echo "------------------------------------------------------"


#打ipa包
echo "--------------------正在导出 .ipa 文件--------------------"
echo '正在 导出 .ipa 文件'
xcodebuild -exportArchive \
-archivePath ${ARCHIVE_PATH} \
-exportPath ${IPA_PATH} \
-exportOptionsPlist ${EXPORT_OPTIONS_PLIST_PATH} \
-allowProvisioningUpdates

# 检查文件是否存在
if [ -f "$IPA_PATH/$SCHEME_NAME.ipa" ] ; then
echo " 导出 ${SCHEME_NAME}.ipa 包成功 🎉 🎉 🎉 "
echo " ipa包路径:$export_path "
else
echo " 导出 ${SCHEME_NAME}.ipa 包失败 😢 😢 😢 "
exit 1
fi

# 输出打包总用时
echo "使用Jenkins打包总用时: ${SECONDS}s "
echo "------------------------------------------------------"


# 将包上传AppStore
cd build-${version}
ipa_path="$SCHEME_NAME.ipa"
# 上传AppStore的密钥ID、Issuer ID
api_key="FFX6T2CD4W"
issuer_id="69a6de70-bd1a-47e3-e053-5b8c7c11a4d1"

echo "--------------------AppStore上传固定参数检查--------------------"
echo "ipa_path = ${ipa_path}"
echo "api_key = ${api_key}"
echo "issuer_id = ${issuer_id}"

# 项目的参数 upload:表示是否上传AppStore
if [ $upload == false ]; then
echo "-------未选择上传AppStore--------"
else

echo "------------------------------------------------------"
echo "-------准备上传AppStore--------"

# 验证
validate="xcrun altool --validate-app -f ${ipa_path} -t ios --apiKey ${api_key} --apiIssuer ${issuer_id} --verbose"
echo "running validate cmd" $validate
uvalidateApp="$($validate)"
if [ -z "$uvalidateApp" ]; then
echo " 校验IPA失败😢 😢 😢 "
echo "------------------------------------------------------"
else
echo " 校验IPA成功🎉 🎉 🎉 "
echo "------------------------------------------------------"

# 上传
upload="xcrun altool --upload-app -f ${ipa_path} -t ios --apiKey ${api_key} --apiIssuer ${issuer_id} --verbose"
echo "running upload cmd" $upload
uploadApp="$($upload)"
echo uploadApp
if [ -z "$uploadApp" ]; then
echo " 传IPA失败😢 😢 😢 "
echo "------------------------------------------------------"
# 发送上传失败邮件通知
mail -s "ipa上传AppStore失败啦 😢 😢 😢 ,请联系管理员" ${notiEmail}
else
echo "上传IPA成功🎉 🎉 🎉 "
echo "------------------------------------------------------"
# 发送上传成功邮件通知
mail -s "ipa上传AppStore成功啦 🎉 🎉 🎉" ${notiEmail}
fi

fi
fi


exit 0

备注:mac电脑需要配置上传相关的密钥,参考文章:使用 xcrun altool 上传ipa

使用

  • 登录Jenkins,选择对应的打包项目

  • 构建一个新的版本

  • 自动打包过程中可进入具体的版本,查看终端日志

遇到的问题

  • 在执行pod 命令时,提示pod command not found

解决方法:在shell脚本最前面加上 #!/bin/bash -l

1
2
#!/bin/bash -l
export LANG=en_US.UTF-8
  • pod install 私有三方库报错

【解决方法】将https://xxxx.git 改成 https://username:password@xxxx.git
这里的username、password就是登录gitlab的用户名+密码

  • code signing报错

报错:Command CodeSign failed with a nonzero exit code
原因:是 Jenkins,ssh 方式到 slave 机上,默认是没有账户的,但是访问钥匙串要求必须有用户身份,所以添加一步输入密码解锁钥匙串,可以给 Jenkins 一个用户身份。
【解决办法】: build 步骤前添加一步解锁钥匙串

1
security unlock-keychain -p "login pwd" ~/Library/Keychains/login.keychain

所以,综上所述,Jenkins自动打包流程如下:

  • Post title:OC底层原理43.2:自动化打包(二)Jenkins + GitLab实现自动化打包
  • Post author:张建
  • Create time:2023-05-09 16:05:56
  • Post link:https://redefine.ohevan.com/2023/05/09/OC底层原理/OC底层原理43.2:自动化打包(二)Jenkins-GitLab实现自动化打包/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
On this page
OC底层原理43.2:自动化打包(二)Jenkins + GitLab实现自动化打包