无论如何,测试打包对于 iOS 开发者而言都是件繁琐枯燥的事情,项目规模小还好,几分钟不过是去喝杯咖啡的时间。但是对于稍微大一点的项目而言,少则十几分钟,多则半小时,在这么长的时间里,你得一直等待Xcode完成 Archive 任务,在此期间还需要你点击几个选项,既费时,又费心。尤其是遇到个别 UI 测试上的小问题,一个像素的调整、一处文案的修改,反复的执行打包操作,脾气再好的工程师都会感到一阵抓狂。

自从去年第一次使用过 Fastlane 之后,打包这项繁琐的工作,就再也不是一项负担。我只需要在 iTerm 里敲一行命令,就完成了从打包到测试平台发布整套流程,比手动发布时间更快,并且这个过程不会影响你当前的任何操作,你仍然可以继续使用 Xcode,或者做任何你想做的事。

本文以目前主流的两大分发平台 Pgyer ( 蒲公英 )Bugly ( 腾讯 Bugly ) 为例,从头搭建一个全自动化分发环境,以及 Fastlane 脚本的示范编写。

本文以下内容的运行环境(2019-12-19 更新):

  • Xcode: 11.1

  • macOS: Catalina 10.15.1

  • Fastlane: 2.137.0

  • Ruby: 2.6.3

需要注意,如果你是第一次使用 Fastlane ,macOS 的系统版本最好保持在 10.15 以上,因为低版本系统所自带的 Ruby 版本过低,在安装过程中会出现问题,如果你不想升级 macOS 版本,必须使 Ruby 保持在 2.4.0 以上

Fastlane

Fastlane 是 Google 的大神 Felix Krause 基于 Ruby 写的一套自动化工具集,能够帮助iOS 和 Android 开发者实现自动化部署,持续集成等工作。Fastlane 的组件包括:

名称 作用
deliver 自动上传截图,APP 的元数据,二进制( ipa )文件到 iTunes Connect
snapshot 自动截图(基于 Xcode 的 UI test)
frameit 可以把截图自动加上边框
pem 自动生成、更新推送配置文件
sigh 用来创建、更新、下载、修复 Provisioning Profile 的工具
produce 自动在 iTunes Connect 或 Apple Developer Center 中建立你的产品
cert 自动创建管理 iOS 代码签名证书
pilot 管理 TestFlight 的测试用户,上传二进制文件
boarding 建立一个添加测试用户界面,发给测试者,可自行添加邮件地址,并同步到 iTunes Connect
gym 自动化编译打包工具
match 证书和配置文件管理工具
scan 自动运行测试工具,并生成 HTML 报告

安装 & 初始化

由于 Fastlane 对 Ruby 的环境有版本要求,如果本机的 Ruby 版本在 2.4.0 以下,建议升级更新 Ruby。

# 查看本机 Ruby 版本
$ ruby --v

更新 Ruby

你可以使用 RVM 或者 Homebrew 来进行 Ruby 的升级更新。

# RVM

# 安装 RVM
$ RVMcurl -L get.rvm.io | bash -s stable

# 查看当前所有可安装的 Ruby 版本
$ rvm list known

# 选择其中一个版本进行安装
$ rvm install ruby-版本号
# Homebrew

# 安装 Homebrew (如果下面的安装链接失效,可以直接访问官网查看 https://brew.sh/)
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

# 升级 Ruby 的最新版本
$ brew upgrade ruby

安装 Fastlane

# 使用 gem 进行安装
$ sudo gem install -n /usr/local/bin fastlane

初始化 Fastlane

cd 到项目目录,执行初始化命令:

$ fastlane init

首先会询问你使用 Fastlane 的目的,这里我们由于只需要搭建自动分发,所以,选择 4

然后根据提示进行操作即可:

初始化完成后提示如下:

安装完成后,你的工程目录下会出现一个名为 fastlane 的文件夹,一个名为 GemfileGemfile.lock 的文件。进入 fastlane 文件夹,打开 Appfile,填入你的 应用标识名开发者账号名

Fastfile 脚本的编写

初始化完成后,Fastlane 就可以投入使用了。Fastlane 整个自动化的核心就是 fastfile 这个脚本执行文件和控制自动化链条的 Action,所以,如果想要完成自动化测试发布,就需要对这个文件进行自定义编写,并处理其相应的 Action。

我们先将自动化测试发布的步骤,按照一个个 Action 进行独立拆分,最后在合并成为完整的一键自动化流程。

我们想要达到的效果是,在终端执行一行 lane 指令后,可以自由选择是否对上传到 Pgyer / Bugly 的测试包展示内容进行自定义修改,如果需要,则允许使用者在终端中输入自定义内容并保存到最终的上传参数中,不需要则直接自动执行打包 + 上传的操作,每次打包完成后,对应 Target 的 Build 版本号自动加一,上传完成后,自动打开浏览器并进入对应平台的测试包分发页面。

基于这些诉求,我们拆分后的步骤大致如下:

  • lane 指令的配置

  • gym Action 的自动打包脚本编写

  • increment_build_number 累加 Build 版本号

  • 自动上传 ipa 到 Pgyer / Bugly 的脚本编写

  • 手动设置参数任务的编写,用于自定义 Pgyer / Bugly 上传参数

  • 浏览器页面打开脚本编写

  • 合并编写好的脚本到统一的lane指令

lane指令的配置

打开 Fastlane 文件夹下的 fastfile,注意,一定不能直接使用文本编辑器打开,会引起自动引号等报错,这里推荐使用 Visual Studio Code 选择 Ruby 文本样式来打开编写。

lane指令的配置非常简单,直接用以下内容覆盖 fastfile 默认的模板:

# 设置平台参数
default_platform(:ios)
platform :ios do

# lane执行指令,使用时直接在终端输入fastlane ad,这里的 ad 可以换成你喜欢的任何名字
lane :ad do

end
end

自动化打包

我们使用 Fastlane 提供的 gym, 这个专门的打包 Action 来对脚本进行编写:

在上一步设置好的lane指令作用域内(也就是lane :ad do - end 中间这部分区域),输入如下内容:

# 指定scheme, 可通过Xcode->Product->Scheme->ManageSchemes查看
scheme = "Your project scheme"
# 当前时间字符串,用于输出文件夹的后缀,遵循 Xcode 的输出规则
currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
# 指定输出文件夹路径, 将ipa_name换成你想要的ipa名称
output_path = "../ipa_name #{currentTime}"
# 指定输出ipa名称
ipa_name = "Your ipa name"

# 自动打ad_hoc测试包
gym(
  # 指定 workspace, 这个参数很重要,否则你还需要手动选择一次打包对象
  workspace:"xxxx.xcworkspace",
  # 指定scheme
  scheme:"#{scheme}",
  # 打包后的 ipa 名称
  output_name:"#{ipa_name}",
  # 是否在运行时自动清理上一次的执行
  clean:true,
  # 指定要打包的配置名
  configuration:"Release",
  # 指定打包所使用的输出方式,目前支持 app-store, package, ad-hoc, enterprise, development, 和 developer-id,即 xcodebuild 的 method 参数
  export_method:"ad-hoc",
  # 最后输出的文件夹路径
  output_directory:"#{output_path}",
)


写好之后,你的 fastfile 应该是这个样子:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer/Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"

  # 自动打ad_hoc测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
end
end

到这里,一个基本的 gym Action 自动打包脚本就编写完毕了。但是仅仅依靠上面这些内容还不足以完成我们想要的打包全自动化流程,现在,我们在执行 fastlane ad 打包之前,还需要手动对每个 Target 中的 Build 版本号进行更改,这非常麻烦,而且如果在某次打包之前忘记了更改,还得打断任务重新执行。

不过不用担心,Fastlane 早已替我们考虑周到。我们只需要在 gym Action 执行之前,也就是在它的前一行加上一行代码即可:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer/Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"

  # Build 自动增加, 会自动的再当前 build version 的基础上 +1, 需要对工程进行额外配置,下文会说明
  increment_build_number
  
  # 自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
end
end

Xcode 工程配置

increment_build_number 是 Fastlane 自带的脚本命令,作用是在当前 build version 的基础上自动 +1,省去了每次打测试包都要手动修改 Build 的工作。

其原理是代替我们调用了 Xcode 自带的自动增加版本号的命令行工具 agvtool。有对 agvtool 感兴趣的可以了解一下具体如何使用

在 fastfile 脚本文件中添加了 increment_build_number 之后,还需要对 Xcode 进行额外的工程配置:

注意:如果有多个 Target,需要对每个Target 都进行下面的设置

设置 Current Project Version & Versioning System

  • TARGETS -> Build Settings

  • Current Project Version 填写当前版本号,最好从1开始

  • Versioning System 选择 Apple Generic ( Xcode 11 以上版本忽略 )

设置 Bundle version & Bundle versions string, short

  • TARGETS -> Info

  • Bundle version 和 第1步设置的 Current Project Version 保持一致即可,可以直接使用 $(CURRENT_PROJECT_VERSION)

  • Bundle versions string, short 是当前应用的 Version 版本号,如果需要自增 Version 再设置 $(MARKETING_VERSION),其对应的脚本参数是 increment_version_number,仅自增 Build 无需设置

将 ipa 包自动上传至 Pgyer/Bugly

由于 Pgyer 和 Bugly 采用的是两套不同的上传策略,所以我们需要分开编写两套上传脚本

Pgyer

安装蒲公英的 Fastlane 插件

$ fastlane add_plugin pgyer

期间会询问一次,选择 y 即可,出现下面提示表示安装成功

安装成功后,在 gym 下面加入蒲公英插件的配置信息:

# 上传到蒲公英
  pgyer(
    # 蒲公英 API Key
    api_key: "xxx", 
    # 蒲公英 User Key
    user_key: "xxx", 
    # 更新描述 (可选)
    update_description: "xxx"
  )

api_keyuser_key,在自己账号下的 应用管理 - App概述 - API 中可以找到,替换到对应的位置即可。蒲公英插件不支持修改测试包名,仅支持更新描述的修改。

此时,你的 fastfile 应该是这样:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"

  # Build 自动增加, 会自动的再当前 build version 的基础上 +1, 需要对工程进行额外配置,下文会说明
  increment_build_number
  
  # 自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
  
  # 上传到蒲公英
  pgyer(
    # 蒲公英 API Key
    api_key: "xxx", 
    # 蒲公英 User Key
    user_key: "xxx", 
    # 更新描述 (可选)
    update_description: "xxx"
  )
end
end

Bugly

Bugly 官方为我们提供了两个 Fastlane 的扩展插件:上传文件和更新文件,由于目前腾讯已经关闭了 Bugly 官网的文档入口,可以直接查看他们的 Github repo 的使用文档

首先点击下载插件,下载完成后,本地会多出两个 ruby 文件,更新文件插件update_app_to_bugly 和 上传文件插件upload_app_to_bugly。然后将下载好的上传文件插件的文件名 upload_app_to_bugly 复制下来,在下一步中会用到。

这时,就需要我们开始编写 upload_app_to_bugly Action 了。

首先,自定义一个 Action,在 cd 到工程根目录(有 fastlane 文件夹的那个)终端中执行如下命令

$ fastlane new_action

输入完之后,Fastlane 会让你输入自定义的 Action 名字,直接粘贴刚才复制好的名字即可。

随后,Fastlane 就会在 fastelane 文件目录下创建一个名为 actions 的文件夹,而文件夹下也会默认有一个名为 upload_app_to_bugly.rb 的 ruby 文件。然后我们把刚才下载好的同名文件直接进行替换就可以了。

upload_app_to_bugly Action 创建成功后,我们需要回到 fastfile 里面对其 Action 内容进行编写,因为 fastfile 的 Action 执行优先级是自上而下的,所以我们需要将 upload_app_to_bugly Action 的内容写在 gym Action 下面:

# 指定输出 ipa 文件路径 
ipa_path = "#{output_path}/#{ipa_name}.ipa"

#上传 Bugly
upload_app_to_bugly(
  # ipa 的文件绝对路径
  file_path:"#{ipa_path}",
  # 应用编号, 用于识别产品的唯一 ID
  app_key:"xxxxx",
  # 用于识别 API 调用者身份, 创建应用时自动获得
  app_id:"xxxx",
  # 应用平台标识, 用于区分产品平台 android:1 iOS:2
  pid:"2",
  # 版本名称, 如有中文必须 UTF-8 格式
  title:"xxxxx",
  # 版本介绍, 如有中文必须 UTF-8 格式
  desc:"xxxxx",
  # 公开范围(1:所有人, 2:密码, 4:管理员, 5:QQ群, 6:白名单, 默认所有人)
  secret:"1",
  # 如果公开范围是"QQ 群"填写 QQ 群号, 如果是"白名单"填写QQ号码, 并使用; 切分开, 5000个以内. 其他场景无需设置
  users:"",
  # 如果公开范围是"密码"需设置
  password:"",
  # 下载上限(大于0, 默认1000)
  download_limit:999
)

这里只列举了必填参数和部分可选参数,腾讯在去年将插件的API文档入口也一并从 Bugly 移除了,如果你想了解更多相关参数的含义,可以在我前搭档写的这篇文章里找到其文档的网页快照。

此时你的 fastfile 应该是这个样子:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"
  ipa_path = "#{output_path}/#{ipa_name}.ipa"

  # Build 自动增加
  increment_build_number

  # 自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )

  # 上传 Bugly
  upload_app_to_bugly(
    file_path:"#{ipa_path}",
    app_key:"xxxxx",
    app_id:"xxxx",
    pid:"2",
    title:"xxxxx",
    desc:"xxxxx",
    secret:"1",
    users:"",
    password:"",
    download_limit:999
  )

end
end

通过控制脚本管理上传参数

每次发布测试包后,都需要在 Pgyer/Bugly 测试分发平台上手动修改,测试包名称和本次更新内容,也就是上一步中,pgyer Action 中的 update_description 参数 和 upload_app_to_bugly Action 中的 title、desc 参数。

如果你完全没有修改的需求,这个 fastfile 实际就可以直接投入使用了。但是我们为了更好的把控测试分发和规范流程,还是需要在每次测试包更新后,对所更新的内容进行一个简要的说明。

下面我们就开始第4个步骤,对手动设置参数任务的编写,在 gym Action 之前,添加 Ruby 代码:

# 设置测试包默认title
version_title = "xxx"
# 设置测试包默认desc
version_desc = "xxxxxx"

begin
  # 选择是否手动设置测试包的标题和描述
  puts "Do you want to manually set the title of the test package & description? (y/n)" 
  res = STDIN.gets.chomp

  if res != "n"
      # 用于 Bugly 显示的测试包标题 (仅使用蒲公英的话,设置标题的部分可以屏蔽掉)
      print Input title:  "
      version_title = STDIN.gets.chomp
      puts "---Title set successfully!---"

      # 用于  Pgyer/Bugly 显示的测试包更新描述
      print "Input description:  "
      version_desc = STDIN.gets.chomp
      puts "---Description set successfully!---"
  end
end

上面这段代码是一段选择任务,会在自动打包执行之前进行一次询问,是否需要手动设置测试包的标题和描述,如果选择 y,则会要求使用者输入测试包的标题和更新描述,如果选择 n 则自动跳过这一步,直接开始打包。

这就避免了在分发新的测试包的时候,还需要修改 update_descriptionAction 或 upload_app_to_bugly Action 脚本参数 或者 打开平台网页 -> 点击内测分发 -> 选择上传的测试包 -> 点击修改,这样繁琐的步骤。

最后,你的 fastfile 应该是这个样子:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer/Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"
  ipa_path = "#{output_path}/#{ipa_name}.ipa"
  version_title = "xxx"
  version_desc = "xxxxxx"
	
  begin
    # 选择是否手动设置测试包的标题和描述
    puts "Do you want to manually set the title of the test package & description? (y/n)" 
    res = STDIN.gets.chomp

    if res != "n"
	# 用于 Bugly 显示的测试包标题
	print "Input title:  "
	version_title = STDIN.gets.chomp
	puts "---Title set successfully!---"

	# 用于 Pgyer/Bugly 显示的测试包更新描述
	print "Input description:  "
	version_desc = STDIN.gets.chomp
	puts "---Description set successfully!---"
    end
 end
	
  #build自动增加
  increment_build_number
	
  #自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
	
  # 上传到蒲公英 (两种上传平台二选一)
  pgyer(
    # 蒲公英 API Key
    api_key: "xxx", 
    # 蒲公英 User Key
    user_key: "xxx", 
    # 更新描述 (可选)
    update_description: "#{version_desc}"
  )
  
  # 上传Bugly (两种上传平台二选一)
  upload_app_to_bugly(
    file_path:"#{ipa_path}",
    app_key:"xxxxx",
    app_id:"xxxx",
    pid:"2",
    title:"#{version_title}",",
    desc:"{version_desc}",
    secret:"1",
    users:"",
    password:"",
    download_limit:999
  )

end
end

完善脚本

最后一步,我们需要将这个 “裸奔” 的脚本进行一些必要的点缀,在关键步骤上做一些处理:

添加输出 log

我们在一些关键步骤上,比如更新 build_number 之后、打包完成开始上传到 Pgyer/Bugly 的执行节点上,加上一些提示性的 log, 对查看打包上传进度是很有帮助的:

你可以选择使用 puts 进行打印,它会在打印后自动切换光标到下一行,如:

puts "---Build number updated successfully !---"

也可以使用 print 进行打印,它在打印后会将光标停留在当前这行,如:

print "Input title:  "

让关键 log 以颜色进行区分

如果不进行颜色区分,脚本在执行中密密麻麻的 log 全部都是同一个颜色,让人眼花缭乱,那么我们添加的输出 log 就是白费功夫了,所以我们需要对关键 log 加以颜色进行渲染,如:

# 设置文本颜色
def colorize(text, color_code)
  "\e[#{color_code}m#{text}\e[0m"
end

# 绿色
def green(text); colorize(text, 32); end
# 深紫色
def magenta(text); colorize(text, 35); end
# 青蓝色
def cyan(text); colorize(text, 36); end

这些都是 Ruby 当中常用的颜色值设置方法,更多颜色的设置方法可以参考 这里

使用方法,以上面的 log 为例:

puts ""+ green("---Build number updated successfully !---") +""

最终这行 log 在终端中就会以绿色的文本进行显示了。

通过这些简单的点缀,我们来最后完善一下这个自动化打包发布脚本:

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer/Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"
  ipa_path = "#{output_path}/#{ipa_name}.ipa"
  version_title = "xxx"
  version_desc = "xxxxxx"
  
  def colorize(text, color_code)
    "\e[#{color_code}m#{text}\e[0m"
  end

  def green(text); colorize(text, 32); end
  def magenta(text); colorize(text, 35); end
  def cyan(text); colorize(text, 36); end
	
  begin
    # 选择是否手动设置测试包的标题和描述
    puts ""+ magenta("Do you want to manually set the title of the test package & description? (y/n)") +"" 
    res = STDIN.gets.chomp

    if res != "n"
	# 用于 Bugly 显示的测试包标题
	print ""+ magenta("Input title:  ") +""
	version_title = STDIN.gets.chomp
	puts ""+ green("---Title set successfully!---") +""

	# 用于 Pgyer/Bugly 显示的测试包更新描述
	print ""+ magenta("Input description:  ") +""
	version_desc = STDIN.gets.chomp
	puts ""+ green("---Description set successfully!---") +""
    end
  end
	
  # Build 自动增加
  increment_build_number
  puts ""+ green("---Build number updated successfully !---") +""
	
  # 自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
	
  # 上传到蒲公英 (两种上传平台二选一)
  puts ""+ cyan("---Start uploading ipa to Pgyer---") +""
  pgyer(
    # 蒲公英 API Key
    api_key: "xxx", 
    # 蒲公英 User Key
    user_key: "xxx", 
    # 更新描述 (可选)
    update_description: "#{version_desc}"
  )
  
  # 上传Bugly (两种上传平台二选一)
  puts ""+ cyan("---Start uploading ipa to Bugly---") +""
  upload_app_to_bugly(
    file_path:"#{ipa_path}",
    app_key:"xxxxx",
    app_id:"xxxx",
    pid:"2",
    title:"#{version_title}",",
    desc:"{version_desc}",
    secret:"1",
    users:"",
    password:"",
    download_limit:999
 )

end
end

完成后打开浏览器

我们需要在上传完成后,自动打开蒲公英 / Bugly下载页,只需要在脚本的最后插入下面的脚本内容,即可自动打开默认浏览器,并跳转到对应平台的下载页

  # 打开蒲公英 / Bugly下载页
  puts ""+ cyan("--- Open Pgyer/Bugly download page ---") +""
  system("open", "xxxx") # xxxx 为下载页 url

最终的脚本内容

default_platform(:ios)
platform :ios do

# 一键打包上传到 Pgyer/Bugly
lane :ad do
  scheme = "Your project scheme"
  currentTime = Time.new.strftime("%Y-%m-%d %H-%M-%S")
  output_path = "../ipa_name #{currentTime}"
  ipa_name = "Your ipa name"
  ipa_path = "#{output_path}/#{ipa_name}.ipa"
  version_title = "xxx"
  version_desc = "xxxxxx"
  
  def colorize(text, color_code)
    "\e[#{color_code}m#{text}\e[0m"
  end

  def green(text); colorize(text, 32); end
  def magenta(text); colorize(text, 35); end
  def cyan(text); colorize(text, 36); end
	
  begin
    # 选择是否手动设置测试包的标题和描述
    puts ""+ magenta("Do you want to manually set the title of the test package & description? (y/n)") +"" 
    res = STDIN.gets.chomp

    if res != "n"
	# 用于 Bugly 显示的测试包标题
	print ""+ magenta("Input title:  ") +""
	version_title = STDIN.gets.chomp
	puts ""+ green("---Title set successfully!---") +""

	# 用于 Pgyer/Bugly 显示的测试包更新描述
	print ""+ magenta("Input description:  ") +""
	version_desc = STDIN.gets.chomp
	puts ""+ green("---Description set successfully!---") +""
    end
  end
	
  # Build 自动增加
  increment_build_number
  puts ""+ green("---Build number updated successfully !---") +""
	
  # 自动打 ad_hoc 测试包
  gym(
    workspace:"xxxx.xcworkspace",
    scheme:"#{scheme}",
    output_name:"#{ipa_name}",
    clean:true,
    configuration:"Release",
    export_method:"ad-hoc",
    output_directory:"#{output_path}",
  )
	
  # 上传到蒲公英 (两种上传平台二选一)
  puts ""+ cyan("---Start uploading ipa to Pgyer---") +""
  pgyer(
    # 蒲公英 API Key
    api_key: "xxx", 
    # 蒲公英 User Key
    user_key: "xxx", 
    # 更新描述 (可选)
    update_description: "#{version_desc}"
  )
  
  # 上传Bugly (两种上传平台二选一)
  puts ""+ cyan("---Start uploading ipa to Bugly---") +""
  upload_app_to_bugly(
    file_path:"#{ipa_path}",
    app_key:"xxxxx",
    app_id:"xxxx",
    pid:"2",
    title:"#{version_title}",",
    desc:"{version_desc}",
    secret:"1",
    users:"",
    password:"",
    download_limit:999
  )

  puts ""+ green("---ipa to upload successfully !---") +""

  # 打开蒲公英 / Bugly下载页
  puts ""+ cyan("--- Open Pgyer/Bugly download page ---") +""
  system("open", "xxxx") # xxxx 为下载页 url

end
end

现在,这个 fastfile 才算正式宣告完成了,让我们来看看使用效果。

使用

首先在终端中 cd 到你项目目录,也就是有 fastlane 文件的那一层,执行:

$ fastlane ad

当 Fastlane 的小火箭开始出现,就表明 lane 指令开始执行了,以上传到 Pgyer 为例:

首先会询问是否需要修改更新描述,这里示范输入 "Fastlane测试"

输入完成后回车,继续执行,递增 Build 版本号

随后开始执行 gym 配置命令,打包开始

Archive 完成时,会显示当前打包的类型

打包完成后,导出 ipa、dSYM 等文件到指定输出路径,随后开始上传到 Pgyer

上传完成后,会自动打开默认浏览器并跳转到下载页面,并显示当前耗时

进入测试分发的下载页面,你就可以看到已经上传好的测试包了,直接复制链接地址或者 QRCode 给测试人员就可以了。

打包完成后的输出文件会在你指定的输出路径出现,这个文件在上传成功后直接删除就可以了。

当然最后的分发以及删除操作你也可以写在脚本中一起帮你执行。

至此,Fastlane + 指定平台的全自动化部署测试发布就全部搭建完毕了。同理,上传至 AppStore 一样可以使用 Fastlane 完成自动化部署,有了上面这些经验,就可以很轻松的配置完成了,亲手去尝试和体验 Fastlane 的便捷吧。

后记

除了 gym ,也可以直接通过 shell 脚本来执行 Fastlane,想了解更多使用上的配置,可以参考 官方文档

希望 Fastlane 能够帮助更多的工程师解放双手和时间。

参考:

fastlane docs

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

使用 Fastlane 上传 App 到蒲公英