Fastlane 自动化打包并发布 iOS 项目

打包一个iOS项目大致就是给一个编译好的app和对应的描述文件,用签名证书签名导出。那么除项目代码外的两样东西就是

  • 签名证书,给开发者账号下的所有项目使用,有开发和分发两种
  • 描述文件,每个项目对应的文件,且每个项目都可以有开发、分发两类描述文件,而分发有两种,一种是给有限设备使用的 ad-hoc 类型,一种是发布到 TestFlightApp storeapp-store 类型

这两样东西手动获取是非常繁琐的,项目越多越繁复。显然都是些固定的、重复的步骤,Fastlane 能很好地完成这部分工作,而且有很多不同的实践方式。

获取、管理所有项目的签名证书和描述文件

这个可以在每个项目里作,但每年证书过期的时候手动执行一行命令也不是很好的体验。所以我会建一个 fastlane 项目来专门管理证书,使用 Match 这个 Action。

先去 GitHub 建个私有仓库,再在本地建个空白文件夹,在这个文件夹录下执行 fastlane init ,建立一个空白的项目。

配置 MATCH_PASSWORD 环境变量,用于fastlane设置证书的密码

在生成的 fastlane文件夹里新建一个 Matchfile 文件,加入以下内容

1
2
3
4
5
## 刚在 GitHub 建的库
git_url("https://github.com/username/cer")
storage_mode("git")
## 苹果账号
username("youremail@gmail.com")

在 Fastfile 中编辑大致如下

1
2
3
4
5
6
7
8
9
10
11
default_platform(:ios)

platform :ios do
# lane后面这个 bundleid 这个随便改,一个名字,保证在这个文件里是唯一即可
lane :bundleid do
# 改 app_identifier 即可
match(type: "development", app_identifier: "com.domain.bundleid")
match(type: "adhoc", app_identifier: "com.domian.bundleid")
match(type: "appstore", app_identifier: "com.domain.bundleid")
end
end

接着执行 fastlane bundleid ,根据提示输入密码,双重认证码,fastlane 就会登录到苹果开发者中心,检查各种签名证书是否存在,不存在就自动请求生成再下载,再去下载(不存在就生成)app_identifier 的各种描述文件,然后把这些文件 push 到刚才创建的 GitHub 仓库里。

如果账号还有别的开发者账号权限,比如公司的,那么上述步骤还会要选择 team,可以在 Matchfile 中加入 team_id(“xxxxxxx”),以后就不用选择了。

以上,生成获取了签名证书和描述文件,并保存到 Github 仓库备用。

打包并发布项目

假定要打个包给内部测试,可选的方式有 ad-hoc 或 testflight。

adhoc,也就是需要提前收集测试设备id给开发者中心,再重新获取描述文件,match 里面加个 force: true 就是重新生成描述文件。(其实收录设备id这个步骤也可以让 fastlane 作,不过本文不会就这展开。)

首先在项目根目录下执行 fastlane init ,选择生成一个发布 testflight 的项目,生成的 fastlane 文件夹中的 Appfile 要有以下字段,没有的自行加上

1
2
3
4
app_identifier("com.domian.bundleid") # The bundle identifier of your app
apple_id("youremail@gmail.com") # Your Apple email address
itc_team_id("118353632") # App Store Connect Team ID
team_id("BXJDJVNDK") # Developer Portal Team ID,账号有多team权限才需要

Fastfile 中还是使用 Match 来获取证书和描述文件,readonly 加不加都无所谓,只是保证不产生新的签名证书和描述文件

1
2
3
4
5
6
match(
git_url: "https://github.com/username/cer",
type: "adhoc",
app_identifier: "com.domian.bundleid",
readonly: true
)

接着是编译打包

1
2
3
4
5
build_app(
workspace: "bundleid.xcworkspace",
scheme: "bundleid",
export_method: "ad-hoc" #这行删掉就是 app-store
)

接着是发布,这个一般是发布到内部平台或蒲公英之类的地方,蒲公英有对应 Action,配置一下密钥即可,我平时是发布到自建的平台上,一句 curl 命令即可。

Fastfile 总体大致如下

Ad-hoc

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
default_platform(:ios)

platform :ios do
desc "Push a new beta build"
lane :adhoc do
increment_build_number
match(
git_url: "https://github.com/username/cer",
type: "adhoc",
app_identifier: "com.domian.bundleid",
readonly: true
)
build_app(
workspace: "bundleid.xcworkspace",
scheme: "bundleid",
export_method: "ad-hoc"
)

ipa_file_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
puts "==========================上传到apphost=========================="
shellStr = "curl --form file_nick_name=bundleid --form file=@" + ipa_file_path + " https://xxxx.com/api/pkgs -O -#"
exec(shellStr)
# 清理build的产物
clean_build_artifacts
end
end

TestFlight

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
default_platform(:ios)

platform :ios do
desc "Push a new TF build"
lane :release do
increment_build_number
match(
git_url: "https://github.com/username/cer",
type: "appstore",
app_identifier: "com.domian.bundleid",
readonly: true
)
build_app(
workspace: "bundleid.xcworkspace",
scheme: "bundleid"
)
upload_to_testflight(skip_waiting_for_build_processing: true)
# 清理build的产物
clean_build_artifacts
end
end

如果要保留 build 的产物,符号表和ipa,删除clean_build_artifacts即可,要保留每次build的内容,那就如下所示,不过记得编辑 .gitignore 文件,不然就把这些都提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
default_platform(:ios)

platform :ios do
desc "Push a new TF build"
lane :release do
time = Time.new.strftime("%Y-%m-%d-%H:%M:%S")
output_path = "fastlane/archive/adhoc/" + time
increment_build_number
match(
git_url: "https://github.com/username/cer",
type: "appstore",
app_identifier: "com.domian.bundleid",
readonly: true
)
build_app(
workspace: "bundleid.xcworkspace",
scheme: "bundleid",
output_directory: output_path
)
upload_to_testflight(skip_waiting_for_build_processing: true)
# 清理build的产物
# clean_build_artifacts
end
end

以上就是如何利用 fastlane 完成 iOS 项目的打包和发布。

至于其它文章都会提到的,申请个 app 专用密码,添加 FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD 到环境变量,在执行 fastlane spaceauth -u xxxx@gmail.com 获取session,添加 FASTLANE_SESSION 到环境变量这个操作,有一段时间可以不用输密码和双重认证码,有需要可以尝试一下。

但要说明的是,这个session的有效期非常飘忽,几小时到一个月不等,事实上我就没试过超过一天的。但设置 FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD 或 FASTLANE_PASSWORD(appleid的密码) 后就肯定不用输入密码了,最多只需要输入双重认证码。顺带一说,现在appleid 的双重认证是强制开启不能关闭的。