和重复劳动说再见-使用fastlane进行iOS打包

fastlane00

背景

初识fastlane

fastlane是一个通过简单命令来完成诸如截图、获取证书、编译、导出安装包、提交iTunesConnect等一系列操作的工具,它同时支持iOS和Android。
你能够通过简单的方式配置流程进行的顺序,并通过非常简单的命令执行其中的一个流程。当然它的简单并不代表功能也简陋,有开源社区的支持,更新迅速且有很多功能能够满足你的需求。
fastlane01

为什么使用它

之前我们使用的是jenkins内的Xcode integration进行编译工作,但是其更新比较慢(至2017.12.20还未支持Xcode9),Xcode大版本更新后出现无法继续使用的问题。
后改用fastlane,发现其使用和配置还算简单,有开源社区支持,更新迅速功能强大。且相比jenkins里的插件,fastlane可以单独使用,也可以被多种CI接入

配置使用环境

fastlane使用的是ruby环境且对ruby有版本要求(官网要求是ruby2.0以上),所以如果需要的话更新一波ruby,然后通过gem安装fastlane。

更新ruby

更新ruby使用的是RVM工具,在命令行进行如下操作,安装时可能出现进度不动,多半可能是因为被墙了。

1
2
3
4
5
6
7
8
#安装RVM工具
RVMcurl -L get.rvm.io | bash -s stable

#列出可安装的ruby版本(有原始的ruby也有其他版本的版本)
rvm list known

#根据刚才列出的ruby版本,安装一个ruby版本
rvm install ruby-xxxxx(xxx为版本号)

列出来ruby的版本,选择#MRI Rubies这一大类下面的,我装的是2.4的版本
fastlane02

因为我之前已经安装过了,所以提示是已经安装成功
fastlane03

安装fastlane

如果ruby版本满足要求,可以直接在命令行执行以下命令安装fastlane,这个安装比较顺利没出现报错,如果有报错可以根据原因搜索一下解决办法。

1
2
#安装fastlane
sudo gem install -n /usr/local/bin fastlane

配置fastlane

使用的环境搭建好了,就可以进行这一步来配置fastlane了。

初始化

执行默认的初始化

1
2
cd 项目目录
fastlane init

根据提示输入信息,这一步我没有按照提示处理,因为在有多个BundleID多个target的工程上使用,实际上生成的配置还是要修改的。如果你的项目只有一个bundle id也只有一个开发者账号的话,可以直接遵循官方的步骤配置。

fastlane06

初始化完成后可以看到项目目录里多出了一个fastlane文件夹,内有两个比较重要的文件AppfileFastfile
fastlane07
fastlane08

大致流程

通过在命令行执行fastlane [lane-name]以执行fastlane/Fastfile中的一个lane
这个操作会依次从.env文件Appfile文件Deliverfile文件读取配置信息,最后由Fastfile中的逻辑来进行工作。

配置和使用

fastlane可以通过配置 .env文件、Appfile、Deliverfile、Fastfile 来完成各种工作。

其中Fastfile是最核心的用来控制流程走向的配置文件,.env和Appfile可以辅助Fastfile来设置一些参数,Deliverfile可用于配置提交iTunesConnect的一些参数。

需要查看,样例配置可直接前往下载样例配置

Appfile

Appfile是用来配置一些类似于AppleID、BundleID参数(参数是fastlane已经定义好的,新增的并没有用,如果想新增变量需要使用.env方式),可以在Fastfile中使用,AppleID、BundleID等其实会被一些actions直接调用,并不需要写出来传递。

普通配置方式

直接在Appfile里填写app_identifier、apple_id、team_id等,然后根据lane的不同可以设置成不同。

1
2
3
4
5
6
7
8
9
10
11
# 默认配置
app_identifier "com.devhy.test"
apple_id "devhy1@xxxx.com"
team_id "xxxxxxxxx1"

# 如果lane是ent换成Dev的配置
for_lane :ent do
app_identifier "com.devhy.testDev"
apple_id "devhy2@xxxx.com"
team_id "xxxxxxxxx2"
end

使用.env配置方式

.env这个文件的作用是作为环境变量的配置文件,在fastlane init进行初始化后并不会自动生成,如果需要可以自己创建。

执行时默认会读取.env.env.default文件里的配置。通过执行fastlane [lane-name] --env [envName]来指定使用配置文件.env.[envName],读取顺序是.env -> .env.default -> .env.<envName>,相同的变量名会被后面的覆盖。

如我建了文件.env.myDev,里面写了一些参数,那在执行的时候使用fastlane [lane-name] --env myDev即可,想在Appfile、Deliverfile、Fastfile等调用,直接使用ENV['keyName']即可

1
2
3
4
5
6
7
8
9
# .env.myDev文件
# bundle id
App_Identifier = "com.devhy.testDev"
# 开发者账号
Apple_Id = "xx2@xxxx.com"
# 开发者TeamId
Team_Id = "xxxxxxxxx2"
# project的target scheme名称
Scheme = "HYTestDev"
1
2
3
4
# Appfile使用.env方式直接读取变量即可
app_identifier ENV['App_Identifier']
apple_id ENV['Apple_Id']
team_id ENV['Team_Id']

注意:因为是.env文件是.开头文件,默认是在finder中隐藏的,需要通过执行一下命令来显示

1
2
3
4
# 设置隐藏文件可见
defaults write com.apple.finder AppleShowAllFiles TRUE
# 重启finder服务以生效
killall Finder

配置方式对比

普通配置方式:简单易懂,但不能自定义变量,且每个lane想不一样都要写一个for_lane
.env配置方式:功能性强,但配置起来稍微麻烦一点

Deliverfile

Deliverfile是用来配置上传到iTunesConnect所需信息的,由于我们主要用fastlane来打包,发布是手动将ipa包提交审核,由于没有进行过尝试所以该文件配置方式就不叙述了。

Fastfile

Fastfile是对流程进行控制的核心文件,需要设定支持的平台和在一些环节里需要做的事情。

基本结构

Fastfile主要是根据设定的平台,可以在before_all、after_all、error中做一些操作 以及 建立一些lane作为关键的执行逻辑,可以在其中使用fastlane内置的action,也可以调用自建action,还可以调用别的lane

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
# 因为fastlane存在新老版本兼容问题,所以一般会指定fastlane版本
fastlane_version "2.62.0"
default_platform :ios

platform :ios do
# 所有lane执行之前,可以做如执行cocoapods的pod install
before_all do
cocoapods
end

# 名字叫ent的lane,命令行里执行fastlane ent
lane :ent do
# 执行一些action,如cert下载证书,sigh下载pp文件,gym进行编译和导出包
end

# 执行fastlane store即可
lane :store do
# 调用一些action

# 调用别的lane,比如send_msg
send_msg
end

lane :send_msg do
# 调用一些action
end

# 所有lane完成之后,可以适用参数lane来区分
after_all do |lane|
end

# 所有lane失败之后,可以适用参数lane来区分
error do |lane, exception|
end
end

Fastfile样例

下面的Fastfile样例是配置了.env+Appfile后进行编写,因为这样在配置action时,可以省去一些入参。
因为使用了Appfile,cert的username、team_id 以及 sigh的app_identifier、username、team_id 可以不用传入了,fastlane在执行时会自己去从Appfile里取。以及之前在.env环境配置中设定了一个Scheme的字段,那么gym的scheme我们可以使用ENV[‘Scheme’]来调用。

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
fastlane_version "2.62.0"
default_platform :ios

platform :ios do

before_all do
cocoapods
end

lane :store do
# action(cert),下载[开发者证书.cer]
# 下载的文件会存在项目根目录的build文件夹下
# fastlane会让你在命令行登录开发者账号,登录成功后,会在你的[钥匙串]中创建一个 {deliver.[username]} 的登录账户
cert(
# Appfile设置了这边就可以不用了
# username: "devhy2@xxxx.com",
# team_id: "xxxxxxxxx2",

# 下载.cer文件的位置
output_path: "build",
)

# action(sigh),下载[安装app匹配的Provision Profile文件(pp文件)]
# 建议自己去苹果开发者网站证书中手动处理一波provision_profile
# 建议用 bundleId_导出方式 来命名比如:
# 企业包pp文件叫 testDev_InHouse.mobileprovision
sigh(
# Appfile设置了这边就可以不用了
# app_identifier: "com.devhy.testDev",
# username: "devhy2@xxxx.com",
# team_id: "xxxxxxxxx2",

# 下载pp文件的位置
output_path: "build",
# 自动下载签名时,adc里pp名字,不写也可以会根据你的bundle id、adhoc与否去下载最新的一个
# provisioning_name: "testDev_InHouse",
# 仅下载不创建,默认是false
readonly: true,
# 因为是根据BundleID下载,导致adhoc和appstore会优先appstore,导致最后导出报错,如果是adhoc包请设置为true
adhoc: true,
)

# 编译配置,编译的scheme,导出包方式
gym(
# 使用.env配置的环境变量
scheme: ENV['Scheme'],
# app-store, ad-hoc, package, enterprise, development, developer-id
export_method: "enterprise",
# 输出日志的目录
buildlog_path: "fastlanelog",
# 输出编译结果
output_directory: "build",
include_bitcode: false
)
end

after_all do |lane|
end

error do |lane, exception|
end
end

actions

在fastlane中使用的诸如cer()、sigh()、gym()都是action,其本质是预先写好的ruby脚本(如:sigh.rb),fastlane中有很多已经写好的actions,当然也可以自己进行编写。

命令行常用的操作有:

  1. 查看所有Action
    fastlane actions
  2. 查看某个Action的参数说明
    fastlane action [action_name]如(fastlane action gym)

配置后的使用

编写完各种配置后怎么使用?其实使用方法还是比较简单的,
不使用.env配置,执行fastlane [lane_name]即可
使用某个.env配置,执行fastlane [lane_name] --env [env_name]即可

比如我在需要执行样例的Fastfile的store,并使用.env.myDev配置,那我可以执行fastlane store --env myDev

进阶使用

options参数传递

在执行shell脚本之类的都是可以传递一些参数的,fastlane也是有的,options就是存储了我们在命令行中执行lane时传递的参数的字典,在befor_allafter_all、各种lane里都可以使用这个options

传递参数

1
2
# 使用key:value来传递一组对应的参数
fastlane ent key:value key2:value2

接收参数

1
2
3
4
5
6
7
8
9
10
11
platform :ios do 
before_all do |lane, options|
#options参数
value = options[:key]
value2 = options[:key2]
end

lane :ent do
...
end
end

private_lane

私有lane其实就像开发的时候的私有方法一样,外部是使用不到的,如在命令行中使用fastlane deal_param是执行不了的,但在Fastfile内部可以调用到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
platform :ios do 
# 相当于全局变量
build_config = "debug"

before_all do |lane, options|
# 调用私有lane deal_param 并将options传递过去
deal_param options
end

lane :ent do
# ...
end

# 私有lane,比如把传入的build参数进行一下处理
private_lane :deal_param do |options|
build_config = build_config ? build_config : "debug"
build_config.capitalize!
end
end

自建Action

执行fastlane new_action,命令行提示输入自建的action名称,输入后fastlane会帮助生成一个action编写的模版ruby文件,在模版中编写自己的Action逻辑,具体因为暂时没有写过,请查看官方的文档。

与jenkins搭配使用

因为fastlane可以在命令行中使用,所以只要在jenkins中,构建的一些环节中使用Excute Sell方式,然后输入fastlane相关的命令即可了。
fastlane-10

其他问题

两步验证

需要在打包机上进行一些配置操作,session有过期时间,打包失败的时候记得去打包机更新一下

  1. 访问 AppleId管理站
  2. 找到 安全 - App 专用密码,生成一个专用密码
  3. 通过环境变量FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD配置专用密码
  4. 执行fastlane spaceauth -u 开发者账号邮箱,按提示获取session信息。
  5. 通过环境变量FASTLANE_SESSION配置session。

环境变量所在目录为~/.bash_profile
进行如下配置:

1
2
export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=专用密码
export FASTLANE_SESSION=session

附录

下载样例配置

AppFile + Fastfile
.Env + AppFile + Fastfile + Options传递参数

参考资料

fastlane - Github
fastlane - 官方文档