Comment on page

fastlane一键打包

#fastlane #持续集成

1. 初始化fastlane

在项目目录下执行命令,并按照提示选择所需功能,输入应用信息以及Apple开发账号信息。
fastlane init
执行完成后,项目目录下会自动生成fastlane文件夹,文件夹中生成两个文件AppfileFastfile
  • Appfile 中包含该应用的基本信息(app id,开发者账号信息)
app_identifier("com.zm.OCTest") # The bundle identifier of your app
apple_id("*********") # Your Apple email address
itc_team_id("*******") # App Store Connect Team ID
team_id("******") # Developer Portal Team ID
# For more information about the Appfile, see:
# https://docs.fastlane.tools/advanced/#appfile
  • Fastfile 中包含持续集成的步骤配置
一个命名的lane代表一个持续集成的任务,每个任务由多个步骤组成,步骤通常是已经定义好的action工具。
执行lane:
fastlane lanename
常用的action工具:
  • match : 证书和配置文件的管理
  • gym(build_app) : 打包和签名
  • poilt(upload_to_app_store):app store 发布
default_platform(:ios)
# 以下是FastFile的配置示例
platform :ios do
desc "Push a new release build to the App Store"
lane :release do
build_app(scheme: "OCTest")
upload_to_app_store(skip_metadata: true, skip_screenshots: true)
end
end
# 一个lane代表一个CI的配置,可以看到release中包括两个步骤build_app,upload_to_app_store。
# build_app,upload_to_app_store 这俩个步骤是fastlane中已经定义好的action工具
接下来,我们会使用matchgympilotfastlane中已经定义好的action。查看某个action具体参数,请使用命令
fastlane action actionName

2. 使用match管理证书

match(sync_code_signing) 在github仓库中加密保存证书和描述配置文件,用于开发成员之间共享
  1. 1.
    在github上创建一个仓库用于保存证书
  2. 2.
    在项目目录下执行fastlane match init,输入仓库地址;在fastlane目录下会生成Matchfile文件,包含match的配置信息
  1. 1.
    执行这些命令fastlane match development, fastlane match adhoc, fastlane match enterprisefastlane match appstore,首次执行自动在apple store connect中创建provisioning file,证书并下载加密保存在git仓库,并上传.
  2. 2.
    其他开发者就可以使用fastlane match命令共享github中的证书和配置文件。

match的参数

  • type: 同步的配置文件类型: appstore,adhoc,development,enterprise,默认 development
  • readonly: 默认false,如果是true,不会生成新的证书和描述配置文件
  • app_identifier: 指定描述配置文件的bundle id;如果不指定则使用 AppFile 中的 app_identifier
  • git_url: 证书保存的github地址
  • keychain_name : 保存证书的keychain,默认login.keychain

在CI中使用match

在一次CI中首先就是要同步证书和描述配置文件:
# match 中需要配置参数
# 证书类型 appstore , adhoc 还是 development
# app id
# kaychain 证书保存的keychain
# git_url 证书保存的github远端库
lane :github_action_testFlight do
match(type: "appstore",
readonly: true,
app_identifier: "com.zm.ZLGitHubClient",
keychain_name: ENV['MATCH_KEYCHAIN_NAME'],
keychain_password: ENV['MATCH_PASSWORD'],
git_url: ENV['MATCH_GITHUB_URL'])
end
# ENV['MATCH_GITHUB_URL'] 是加密保存的参数

3. 使用gym打包,签名

gymfastlane提供的用于构建,打包,签名的action,是build_app的别名。

gym的参数

  • workspace: 如果工程在workspace中需要指定,例如使用cocoapods的工程
  • project: 如果工程不在workspace中指定工程名字
  • schema: schema名
  • clean: 是否在打包前clean工程
  • export_method: 指定打包方式: app-store, ad-hoc, package, enterprise, development, developer-id
  • export_options: 可以指定更详细的打包配置,可以是配置文件路径
  • skip_build_archive: 跳过构建,打包阶段,直接签名;使用archive_path 作为输入
  • skip_archive:仅构建
  • skip_codesigning: 仅构建,打包,不签名
  • archive_path : 读取xarchive的路径
  • output_directory: 保存ipa的目录
  • output_name: 保存ipa的名字

在CI中使用gym

# 使用gym的参数
# 打包的工程
# 打包的方式 app-store,adhoc还是development
# 打包文件的目录
lane :github_action_testFlight do
gym(workspace: "ZLGitHubClient.xcworkspace",
scheme: "ZLGitHubClient",
clean: true,
include_symbols: true,
include_bitcode: true,
skip_build_archive: true,
archive_path: "./fastlane/archive/ZLGitHubClient.xcarchive",
output_directory: "./fastlane/ipa/TestFlight",
output_name: "ZLGitHubClient.ipa",
export_options: {
method: "app-store",
provisioningProfiles: {
"com.zm.ZLGitHubClient" => "*** AppStore com.zm.ZLGitHubClient"
}
})
end

4. 使用pilot上传testfight

pilot 是可以与 TestFlight 交互的 action, 通过 piolt 你可以上传和发布新版本,添加和删除测试员。
pilot 在与 App store 交互之前需要双因素认证,这样就没有办法做自动化;不过苹果在 App Store Connect API 中提供Json Web Token的认证方法;具体在下面会介绍。

pilot参数

  • api_key_path : App Store Connect API Key JSON 文件的路径
  • api_key : App Store Connect API Key, 通过 app_store_connect_api_key action 生成
  • app_identifier : 上传版本的bundle id
  • ipa: 上传的ipa文件路径
# pilot 需要提供apple开发者账号信息,以及上传文件目录
lane :github_action_testFlight do
pilot(
username: "[email protected]",
app_identifier: "com.zm.ZLGitHubClient",
changelog: "release to TestFlight",
ipa: "./fastlane/ipa/TestFlight/ZLGitHubClient.ipa"
)
end

5. 使用App Store Connect API 避免双因素认证

在早先,访问App Store Connect信息需要双因素认证。而在持续集成的过程中一般无法人机交互(例如github-action),导致持续集成无法完成。在WWDC18中,苹果提出了App Store Connect API,提供另外的认证方式。Fastlane也对App Store Connect API提供了支持,具体查看Using App Store Connect API

5.1 使用 App Store Connect

必须拥有访问权限才能访问 App Store Connect API
  1. 1.
    申请访问权限
  1. 1.
    生成API密钥
  1. 1.
    密钥生成后需要关注Issuer ID,密钥 ID以及下载密钥文件(.p8); 密钥文件只能下载一次。

5.2 app_store_connect_api_key

app_store_connect_api_key 是用来为其他 action 生成 App Store Connect API tokenaction; match,pilot以及 deliveraction 都可以使用 App Store Connect API token
  • key_id
  • issuer_id
  • key_filePath: p8文件的路径
  • key_content: p8文件的内容,未编码直接提供需要将回车替换为
  • is_key_content_base64: 是否key的内容经过base64编码
  • in_house: 是app store还是 enterprise
lane :release do
api_key = app_store_connect_api_key(
key_id: "D383SF739",
issuer_id: "6053b7fe-68a8-4acb-89be-165aa6465141",
key_filepath: "./AuthKey_D383SF739.p8",
duration: 1200, # optional
in_house: false, # optional but may be required if using match/sigh
)
# 在piolt中使用app_store_connect_api_key
pilot(api_key: api_key)
end

6. 自动更新build number

如果上传TestFlight的新版本的build number,在TestFlight已经存在了,那么就会上传失败。
Fastlane 也提供了工具去自动更新build number

6.1 获取当前TestFlight中最新版本最新build number

app_store_build_number 可以返回当前已经发售或者正在测试的版本的最新build number
currentBuildNumber = app_store_build_number(
api_key: api_key, # 使用app_store_connect_api_key认证
live: false, # live 为 true 查询已发售的版本,false 查询测试的版本
app_identifier: "com.zm.ZLGithubClient"
)

6.2 设置项目的build number

increment_build_number 可以修改项目的build number
increment_build_number(
build_number: currentBuildNumber + 1
)

7. 完整的CI配置

以下是使用 Github Action 作自动化打包的配置,一些关键性信息使用 Secret保存,Fastlane 通过环境变量读取.
desc "build one TestFlight release on github action"
lane :github_action_testFlight do
# 生成 app store connect api key
api_key = app_store_connect_api_key(
key_id: ENV['APPSTOREAPIKEYID'],
issuer_id: ENV['APPSTOREAPIISSUERID'],
key_content: ENV['APPSTOREAPIKEY'],
duration: 1200, # optional
in_house: false, # optional but may be required if using match/sigh
)
# 创建 key chain 保存 证书
create_keychain(
name: ENV['MATCH_KEYCHAIN_NAME'],
password: ENV['MATCH_PASSWORD'],
default_keychain: true,
unlock: true,
timeout: 3600,
add_to_search_list: true
)
# 同步发布证书
match(type: "appstore",
readonly: true,
app_identifier: "com.zm.*",
profile_name: "*** AppStore com.zm.*",
keychain_name: ENV['MATCH_KEYCHAIN_NAME'],
keychain_password: ENV['MATCH_PASSWORD'],
git_url: ENV['MATCH_GITHUB_URL'])
# 更新build number
build_num = app_store_build_number(
app_identifier: "com.zm.ZLGitHubClient",
live: false,
api_key: api_key
)
increment_build_number(
build_number: build_num + 1
)
# 构建,打包,签名
gym(workspace: "ZLGitHubClient.xcworkspace",
scheme: "ZLGitHubClient",
export_method: "app-store",
clean: true,
include_symbols: true,
include_bitcode: true,
output_directory: "./fastlane/ipa/TestFlight",
output_name: "ZLGitHubClient.ipa")
# 上传 test
pilot(
api_key: api_key,
app_identifier: "com.zm.ZLGitHubClient",
changelog: "release to TestFlight",
ipa: "./fastlane/ipa/TestFlight/ZLGitHubClient.ipa"
)

参考文档