由于iOS打包必须依赖Mac设备,本文将介绍在Jenkins中添加远程Mac节点实现自动化打包
当前已配置Mac节点环境
Mac OS | 12.6.2 | |
---|---|---|
Xcode | 14.2 | |
rvm | 1.29.12 | ruby管理 |
ruby | 2.7.2 | |
cocoapods | 1.11.3 | 用于iOS项目三方库管理 |
fastlane | 2.212.0 | 用于打包发布,账号证书管理 |
jenkins | 2.375.3 | |
openjdk | 11.0.18 |
安装Jenkins
已安装或已部署Jenkins服务可跳过此节
本次在Mac机器上安装,使用Docker安装
下载镜像文件
docker pull jenkins/jenkins
挂载docker卷并启动jenkins
docker run \
--name jenkins \
--privileged=true \
--env hostip=127.0.0.1 \
-d \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins-data:/var/jenkins_home \
jenkins/jenkins
启动后即可 访问 localhost:8080 初始化jenkins,初始化密码获取通过执行一下命令获取
docker exec -it jenkins bash cat /var/jenkins_home/secrets/initialAdminPassword
安装推荐插件
添加Mac节点
安装好Jenkins后,添加一台mac机器为远程打包节点
进入Jenkins – Manage Jenkins – Manage Node and Clouds管理节点界面
Built-In Node 是原始Jenkins的内建节点
选择新建节点 – 创建
配置节点参数
配置远程工作目录
启动方式选择ssh方式
由于我是通过docker 安装jenkins在本机,这里可以使用docker本机地址,如果在远程填写对应ip即可
同时,需要在该mac机器上开启ssh权限,在mac系统设置 – 共享 开启相关权限
jenkins中创建登陆账号密码, 点击添加,将本机登陆账号和密码添加
添加完成
创建jenkins任务
创建相关jenkins任务,配置打包参数
我这里仅配置了分支选择和fastlane执行选择
添加构建脚本
#!/bin/bash -l
echo "选择构建参数$BRANCH,$LANE_OPT"
if [ $LANE_OPT == 'BUILD_BETA' ]
then
echo "构建adhoc发布至蒲公英"
source ~/.zshrc
proxy_on
pod install
proxy_off
fastlane beta
elif [ $LANE_OPT == 'SYNC_DEVICES' ]
then
echo "注册新设备"
fastlane sync_devices
else
echo "没有符合条件"
fi
其中 proxy_on
proxy_off
为代理,没有代理删除此行代码
fastlane sync_devices
、fastlane beta
为 fastlane执行命令,需要在项目中配置fastlane相关设置,后面会提到
钥匙串访问限制需要添加
security -v unlock-keychain -p xxx ~/Library/Keychains/login.keychain-db
xxx为mac登陆密码, 可以添加到~/.zshrc
中,像我这样打包前执行 source ~/.zshrc
即可
如果目录下没有login.keychain-db
, 执行security create-keychain -p xxx ~/Library/Keychains/login.keychain-db
创建
钥匙串设置需要关闭休眠,不然可能造成其他不可控的问题
fastlane安装
安装rvm,选择ruby版本2.7.2
安装fastlane
gem install fastlane -NV
进入项目初始化fastlane,选择4.手动模式
fastlane init
安装版本管理插件、蒲公英插件
fastlane add_plugin versioning
fastlane add_plugin pgyer
开发者证书管理
通过fastlane match
管理开发和生产证书, 提前准备好证书存放的git仓库
fastlane match init
打开 Matchfile
配置相关参数
由于远程仓库禁用ssh,我这里的git地址可以写成 git_url("http://username:psd``@xxx.git``")
提前设置好用户名和密码
执行命令可生成相关证书,也可通过配置fastlane脚本执行相关命令,后面会提到
fastlane match development
fastlane match adhoc
fastlane match appstore
执行完成后会自动上传到配置的git仓库中
fastlane脚本配置
从苹果开发者后台创建添加 App Store Connect API
密钥
获取临时密钥
执行fastlane spaceauth 获取session 用于苹果二次登陆验证(如果已经使用了App Store Connect API
可跳过此节)
fastlane spaceauth -u abcd@mail.com
可以将session保存到jenkins环境变量中,或者添加到mac节点中的环境变量中
注意 session信息有效期仅为一个月,过期后需要重新执行此命令
我的ci和mac节点是同一台机器,可以直接添加到jenkins全局的环境变量中
fastfile文件
下面开始编写fastfile文件,该文件包含具体的打包、证书更新脚本
default_platform(:ios)
platform :ios do
target = "项目target名称"
scheme_name = "项目scheme名称"
output_directory = "./build"
team_id = "xxxxx"
fir_token = ""
pgyer_token = "蒲公英token"
fir_feishu_token = ""
issuer_id = ""
key_id = ""
key_filepath = "./Cers/itc_AuthKey_xxx.p8"
api_key = app_store_connect_api_key(
key_id: key_id,
issuer_id: issuer_id,
key_filepath: key_filepath,
duration: 1200, # optional (maximum 1200)
in_house: false, # optional but may be required if using match/sigh
)
lane :match_all do
desc "下载所需要的证书和描述文件到本地(只读)"
match(api_key: api_key, type: "development", readonly: true)
match(api_key: api_key, type: "adhoc", readonly: true)
match(api_key: api_key, type: "appstore", readonly: true)
end
lane :force_match do
desc "同步证书,如果证书过期或新增了设备,会重新创建证书和描述文件"
match(api_key: api_key, type: "development", force_for_new_devices: true)
match(api_key: api_key, type: "adhoc", force_for_new_devices: true)
match(api_key: api_key, type: "appstore")
end
lane :sync_devices do
desc "注册设备,并更新描述文件"
# devices.txt模板:
# http://devimages.apple.com/downloads/devices/Multiple-Upload-Samples.zip
register_devices(api_key: api_key, devices_file: "./fastlane/devices.txt")
match(api_key: api_key, type: "development", force_for_new_devices: true)
match(api_key: api_key, type: "adhoc", force_for_new_devices: true)
end
lane :beta do
desc "上传到测试版本到蒲公英"
# register_devices(
# devices_file: "./fastlane/devices.txt",
# api_key: api_key,
# team_id: team_id
# )
match(api_key: api_key, type: "adhoc", readonly: true)
increment_build_number
version = get_version_number_from_xcodeproj(
target: target,
build_configuration_name: 'Debug'
)
build = get_build_number_from_xcodeproj(
target: target,
build_configuration_name: 'Debug'
)
# output_name = "#{scheme_name}_dev_#{version}_#{build}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
output_name = "#{scheme_name}.ipa"
gym(
include_bitcode: false,
export_method: "ad-hoc",
export_xcargs: "-allowProvisioningUpdates",
scheme: scheme_name,
configuration: "Release",
# clean: true,
output_directory: output_directory,
output_name: output_name
)
pgyer(api_key: pgyer_token, update_description: "update!")
# fir_cli api_token: fir_token, changelog: "to fir.im #{option[:desc]}", feishu_access_token: fir_feishu_token, feishu_custom_message: "fir.im新版已发 #{option[:desc]}"
end
end
至此可以执行 fastlane beta
即可打包发布到蒲公英, fastlane sync_devices
注册新设备,更新证书
协同证书导出
使用fastlane match 生成的相关证书文件内部进行了加密,所以无法从git仓库中直接下载使用,需要参照fastlane官方文档进行解密才可以使用。或者使用正常match命令获取证书,但这要求新的开发人员的机器上有fastlane环境,不是非常方便。
这里我们可以通过创建一个jenkins任务,在mac节点上运行脚本后直接导出并下载相关文件
创建jenkins任务,添加证书管理的仓库地址,添加构建脚本
#!/bin/bash -l
export_dis_P12() {
local password=$1
local p12_filename=$2
# decrypt private key
openssl aes-256-cbc -k "$password" -in "certs/distribution/$p12_filename.p12" -out dis_key.pem -a -d
# decrypt cert
openssl aes-256-cbc -k "$password" -in "certs/distribution/$p12_filename.cer" -out dis_cert.der -a -d
# convert cert from der to pem
openssl x509 -inform der -in dis_cert.der -out dis_cert.pem
# combine private key + cert into p12 (enter password to secure output p12 file)
openssl pkcs12 -export -out dis_cert.p12 -inkey dis_key.pem -in dis_cert.pem -password pass:"$password"
}
export_dev_P12() {
local password=$1
local p12_filename=$2
# decrypt private key
openssl aes-256-cbc -k "$password" -in "certs/development/$p12_filename.p12" -out dev_key.pem -a -d
# decrypt cert
openssl aes-256-cbc -k "$password" -in "certs/development/$p12_filename.cer" -out dev_cert.der -a -d
# convert cert from der to pem
openssl x509 -inform der -in dev_cert.der -out dev_cert.pem
# combine private key + cert into p12 (enter password to secure output p12 file)
openssl pkcs12 -export -out dev_cert.p12 -inkey dev_key.pem -in dev_cert.pem -password pass:"$password"
}
exportProfile() {
local password=$1
local bundle_id=$2
# decrypt AdHoc profile
openssl aes-256-cbc -k "$password" -in "profiles/adhoc/AdHoc_$bundle_id.mobileprovision" -out "AdHoc_$bundle_id.mobileprovision" -a -d
# decrypt Development profile
openssl aes-256-cbc -k "$password" -in "profiles/development/Development_$bundle_id.mobileprovision" -out "Development_$bundle_id.mobileprovision" -a -d
# decrypt AppStore profile
openssl aes-256-cbc -k "$password" -in "profiles/appstore/AppStore_$bundle_id.mobileprovision" -out "AppStore_$bundle_id.mobileprovision" -a -d
}
PASSWORD="xxxxxx"
DEV_P12_FILENAME="xxxxxx"
DIS_P12_FILENAME="xxxxxx"
BUNDLE_ID="com.xxxxxx.xxxxxx"
export_dev_P12 "$PASSWORD" "$DEV_P12_FILENAME"
export_dis_P12 "$PASSWORD" "$DIS_P12_FILENAME"
exportProfile "$PASSWORD" "$BUNDLE_ID"
zip all_export.zip "AdHoc_${BUNDLE_ID}.mobileprovision" "Development_${BUNDLE_ID}.mobileprovision" "AppStore_${BUNDLE_ID}.mobileprovision" dev_cert.p12 dis_cert.p12
echo "请至工作区下载all_export.zip, 或者访问 http://yourJenkinsIp:8080/job/$JOB_NAME/ws/all_export.zip"
构建后到工作区下载该压缩包