FastLane是一种配置iOS和Android自动化Beta部署和发布的最简单的方法之一。它可以简化一些乏味、单调、重复的工作,像截图、代码签名以及发布App。只需一条命令就可实现从 Xcode 项目到 编译\打包\构建\提交审核。
本文做以下事情:
fastlane 环境搭建
导入ios的xcode项目
对xcode项目进行fastlane初始化
FastLane目录下的主要文件说明
安装fastlane插件
使用fastlane测试部署
Fastlane文件格式的具体解析
配置发布流程
说明:本文将 Apple Dev Center 简称为 ADC; iTunes Connect 简称为 ITC
rvm -v #检查ruby是否安装正常
rvm list known #列出已知ruby版本
rvm install ruby-xxxxx #安装一个最新ruby版本
#如果报错的话
brew install opensslreinstall|
install ruby-xxxxx #注意修改xxxxxx
$ xcode-select --install
如果未安装,终端会开始安装,如果报错误:command line tools are already installed, use "Software Update" to install updates.代表已经安装。
$ sudo gem install -n /usr/local/bin Fastlane
$ fastlane -v #检查版本 Fastlane
fastlane installation at path:
fastlane 2.64.1
OK,安装完成
找到shell profile,一般在 ~/.bashrc, ~/.bash_profile or ~/.zshrc文件里,取决于你的系统,文件的末尾处添加:
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
终端,cd到你的工程目录,然后执行fastlane init:
如果期间报错 Connection reset by peer - SSL_Connect,就需要执行:
$ brew update && brew install ruby # 重装
# 然后重新执行
$ fastlane init
a.期间会遇到:在 "Your Apple ID" 这一步输入苹果开发者账号,会让输入 Apple ID 账号密码(这个信息会存在钥匙串中,后续使用无需再输入密码
b.在“Please confirm the above values”这一步,是问该app是否需要在iTC和ADC中创建,输入 y会自动检测是否需要创建,然后,fastlane 会进行一系列的初始化操作,包括下载 App Store 上的元数据和截屏文件。
c.初始化执行后的结果中肯定会被创建的是Appfile和Fastfile。如果Deliverfile,screenshots和metadata目录没被创建,可以运行deliver init来创建。
d.过程中可以安心的输入密码,所有的密码都加密保存在系统的Keychain里。
a.如果上一步输入N,则没有在 ADC 和 ITC 创建相应信息,初始化完成后的fastlane目录,如下图:
该目录下没有zh-hans文件夹,当然也可以后续创建,执行如下操作即可:
$ fastlane produce init
b.若上一步输入y,则在 ADC 和 ITC 中创建了相应信息,初始化完成后的fastlane目录,如下:
1)Appfile: 存储App公共信息,存放app_identifier,apple_id和team_id用
2)Fastfile:配置管理 lane,自动化执行配置文件
3)这里有个小问题,iTC和ADC中的Team ID是不一样的,在fastlane init中只会自动在Appfile里写入ADC的team_id,所以在这个过程中会不停的问iTC的Team ID,所以在创建完Appfile后,手动在里面添加itc_team_id。
4)Deliverfile:配置应用在 ITC 中的各种信息,和 ICC 中的数据是一一对应的
5)metadata:包含应用在 ITC 中的各种信息
6)screenshots:包含截图数据需要注意的是,metadata 和 Deliverfile,都可以配置 ITC 的数据,但后者优先级高.正如下图:
Fastlane的插件是一个或者一组action的打包,单独发布在fastlane之外。
查看所有插件:$ fastlane search_plugins
需安装以下两个插件:
1)fastlane-plugin-versioning => 用来修改build版本号和version版本号。
PS:定义Build时。直接定义成纯数字,比如100起,每次编译的时候让它自动加一。
3)安装上面的插件
$fastlane add_plugin [name] # 安装方法
$fastlane add_plugin versioning
$fastlane add_plugin firim
构建测试应用,编辑fastfile:
lane :beta do
gym(scheme: "MyApp",
workspace: "MyApp.xcworkspace",
include_bitcode: true)
end
测试运行lane(任务):
$ fastlane beta
如果顺利执行的话,将会在当前文件目录看到一个 MyApp.ipa 文件和对应 MyApp.app.dSYM 文件测试成功。
备注:选择sublime打开,把当前显示样式设置为Ruby
Appfile可以为每个lane提供不同的 app_identifier, apple_id 和 team_id,例如:这里就是为Fastfile中定义的:inhouse设置单独的信息。
app_identifier "com.xxx.xxx" # app的bundle identifier
team_id "XXXXXXXXXX" # Team ID
for_lane :inhouse do
app_identifier "com.bbb.bbb"
team_id "AAAAAAAAAA"
app_identifier "com.xxxx.xxxx" # The bundle identifier of your app
Fastfile就是我们打包,发布到fir,testFlight,appstore等等操作的具体配置文件,Fastfile管理所创建的 lane,它的格式是这样的:
# 自动更新fastlane 工具
# update_fastlane
# fastlane_version => 指定 fastlane的最小版本,在每次执行之后会检查是否有新版本,如果有会在末尾追加新版本提醒
fastlane_version "2.30.1"
# default_platform => 默认使用平台是 ios,也就是说文件可以定义多个平台
default_platform :ios
platform :ios do
before_all do
cocoapods
end
# desc => 一个lane(任务)的描述,一般说明这个lane是做什么的
desc "Runs all the tests"
lane :test do #一个lane就是一个任务,里面是一个个的action组成的工作流。
scan
desc "提交一个新的Beta版本到 Apple TestFlight"
desc "This will also make sure the profile is up to date"
lane :beta do
gym(scheme: "Docment") # Build your app - more options available
pilot
# sh "your_script.sh"
# You can also use other beta testing services here (run `fastlane actions`)
desc "部署一个新版本到App Store"
lane :release do
# match(type: "appstore")
# snapshot
deliver(force: true)
# frameit
# 你可以定义自己的lane
#执行lane成功后的回调
after_all do |lane|
# slack(
# message: "Successfully deployed new App Update."
# )
# 如果流程发生异常会走这里并终止
error do |lane, exception|
# message: exception.message,
# success: false
可以把二进制发布到三个地方:
发布测试版到TestFlight
<a href="https://whlsxl.github.io/#to_app_store">发布到Apple Store</a>
用sublime打开 Fastlane 文件,将内容替换为:
# Minimum version of fastlane
<code>fastlane_version </code>"1.32.1"
<code>default_platform :ios</code>
platform<code> :ios </code>do
<code> </code># 1. 用于描述这个 lane 的工作。一个 lane 是一个按顺序执行的工作流。
<code> desc </code>"Creating a code signing certificate and provisioning profile"
<code> </code># 2. 执行名为 provision 的 lane。
<code> lane :provision </code>do
<code> </code># 3. produce 用指定的 ID、name、语言和版本号创建一个可用于 iTunes Connect 和 Developer Portal 的 app。
<code> produce(</code>
<code> app_name: </code>'ENTER_A_UNIQUE_APP_NAME_HERE'<code>, #将 ENTER_A_UNIQUE_APP_NAME_HERE 替换成一个唯一的 App 名字</code>
<code> language: </code>'English'<code>,</code>
<code> app_version: </code>'1.0'<code>,</code>
<code> sku: </code>'123abc'
<code> )</code>
<code> </code># 4. cert 创建一个新的私钥和签名请求,下载、安装生成的证书并导入到钥匙串。
<code> cert</code>
<code> </code># 5. sigh 创建了一个 provisioning profile。force 参数为 true,则每次运行时都会创建新的 provisioning profile,这样就可以保证每次都使用正确的代码签名证书。
<code> sigh(force: </code>true<code>)</code>
<code> </code>end
<code> error </code>do<code> |lane, exception|</code>
<code> </code># This block is called, if there was an error running a specific lane.
注意:sigh 默认创建的是 App Store 的发布 profile。如果想创建 ad hoc profile,需要使用 sigh(adhoc:true)。如果是开发 profile 则使用 sigh(development:true)。
此时创建了第一个 lane,保存文件,打开终端进入到项目文件夹,输入命令:
fastlane provision
这会让 fastlane 执行 provision lane。大约一分钟左右,fastlane 会问你 iTunes Connect 密码,它会保存到你的 Mac 的钥匙串里。
注意:如果看到错误,例如 “Creation of apps of this type is not available”, 则请登录 iTunes Connect,看一下是否有某些更新的协议需要你确认。
在进行下一步之前,还需要在 Xcode 中进行某些修改。打开 项目的xcode中,切换到 General 页。将 bundle identifier 修改为初始化 fastlane 时输入的 App ID。
在 Build Settings > Code Signing > Provisioning Profile 设为 “ <新的 app ID> AppStore”。然后在 Code Signing Identity 选择和这个 provisioning profile 相对应的 ID:
注意:code signing identity 应该和 provisioning profile 中的 identities 相匹配。这样,当 gym 编译 IPA 文件时会使用新创建的 provisioning profile。
登录进 iTunes Connect,此时app 已经创建好了;
打开 fastlane 文件夹下的 Snapfile 文件,将内容替换为:
# A list of devices you want to take the screenshots from
devices([
"iPhone 4s",
"iPhone 5",
"iPhone 6",
"iPhone 6 Plus"
])
# A list of supported languages
languages([
'en-US',
'fr-FR'
])
# Where should the resulting screenshots be stored?
screenshots_path "./screenshots"
# Clears previous screenshots #会清空上次创建的截屏图。
clear_previous_screenshots
# Latest version of iOS
ios_version '9.1'
保存、关闭文件。打开 Fastfile 文件,在 error do |lane, exception| 一句上面加入:
这里创建了一个新的 lane,名为 screenshot,并使用 snapshot 命令根据在 Snapfile 文件中输入的配置创建截屏图。保存文件,在终端窗口中输入:
fastlane screenshot
注意:snapshot 为了截取屏幕,需要调用 Snapfile 中列出的设备类型所对应的模拟器。如果缺少了一种或多种模拟器,你要 Xcode 中通过 Window\Devices 菜单来添加相应的模拟器。左下角的 + 号按钮就是用来添加新模拟器的。
此时,项目文件夹下面的 fastlane 目录,会看到多了一个 screenshots 子目录,还会发现一个 screenshots.html 文件。打开这个文件,可以浏览所有的屏幕截图。
打开 Fastfile,在 screenshot lane 之后添加:
desc "Create ipa" lane :build do gym end
这里创建了一个 lane 叫做 build,它使用 gym 命令创建签名的 ipa 文件。保存 Fastfile,打开终端窗口,进入 项目文件夹,输入命令:
<code>fastlane build</code>
这会执行 build lane,开始编译。一旦编译完成,打开 mZone 项目文件夹。你会看到签好名的 ipa 文件:
要上传屏幕截图、元数据和 IPA 文件到 iTunes Connect,可以使用 deliver 命令,它已经包含在 fastlane 中了。
首先,需要用 deliver 来初始化项目。在终端窗口,进入项目文件夹输入命令:
deliver init
执行完成,在 summary 栏中,你会看到 deliver 已经自动检测到 ipa 文件和屏幕截图的位置。打开 Fastfile 在 build lane 后面添加:
<code>desc "Upload to App Store" lane :upload do deliver end</code>
在终端窗口中,输入命令:
<code>fastlane upload</code>
通过这个命令,fastlane 会创建一个 html 文件,它将以 html form 表单的形式上传文件。登录你的 iTunes Connect。所有的屏幕截图、描述、版本 build 1.0 都应当上传就绪。
剩下来的事情就是点击 “Submit for Review” 按钮。 deliver 可以自动提交 app 去审核,但你需要修改 upload lane:
desc "Upload to App Store and submit for review"
lane :upload do
deliver(
submit_for_review: true
)
lane :deploy do
# 如果你用 pod install
cocoapods
# 如果你没有申请adhoc证书,sigh会自动帮你申请,并且添加到Xcode里
# 不带adhoc参数,sigh会自动生成App Store证书(公司或个人帐户)
sigh
# 以下两个action来自fastlane-plugin-versioning,
# 第一个递增 Build,第二个设定Version。
# 如果有多个target,就必须指定target的值,否则它会直接找找到的第一个plist修改
#建议每一个打的包的Build都要不一样,这样crash了拿到日志,可以对应到ipa上
increment_build_number_in_plist(target: [target_name])
increment_version_number_in_plist(
target: [target_name],
version_number: '7.1.3'
)
#gym用来编译ipa,指定输出目录
gym(
output_directory: './build',
# 上传所有信息到App Store
deliver(force: true)
# You can define as many lanes as you want
desc "Deploy a new version to the App Store"
lane :release do |op|
increment_version_number(version_number: op[:version]) #根据入参version获取app版本号
increment_build_number(build_number: op[:build]) #将build号设置与app版本号相同
# 设置app的info.plist文件项
set_info_plist_value(path: "./xxx/Info.plist", #info.plist文件目录
key: "UIFileSharingEnabled",
# key,将plist文件以Source Code形式打开可查询对应的key
value: false) # value
# 设置自定义plist文件项,用于给app配置不同的服务器URL
set_info_plist_value(path: "./xxx/hostAddress.plist",
key: "host",
# 更新Provisioning Profile
# 在项目当前目录下创建provisions文件夹,并将App Store版本的.mobileprovision文件保存在里面,名称随意。
update_project_provisioning(profile: "./provisions/appstore.mobileprovision")
# 更新项目团队
update_project_team(path: "xxx.xcodeproj",
teamid: "5JC8GZ432G")
# 开始打包
gym(use_legacy_build_api: true,
output_name: "appstore", # 输出的ipa名称
silent: true, # 隐藏没有必要的信息
clean: true, # 在构建前先clean
configuration: "Release", # 配置为Release版本
codesigning_identity: "iPhone Distribution: xxx Co.,Ltd. (5JC8GZ432G)", # 代码签名证书
buildlog_path: "./fastlanelog", # fastlane构建ipa的日志输出目录
output_directory: "/Users/xxx/Desktop") # ipa输出目录
desc "Build a new version use the ceshi"
lane :ceshi do |op|
increment_version_number(version_number: op[:version])
increment_build_number(build_number: op[:build])
set_info_plist_value(path: "./xxx/Info.plist",
key: "UIFileSharingEnabled",
value: true)
value: "https:/ceshiServer:xx/xxx/xxx")
# 将Development版本的.mobileprovision文件保存在里面,名称随意。
update_project_provisioning(profile: "./provisions/development.mobileprovision")
output_name: "ceshi",
silent: true,
clean: true,
configuration: "Debug",
buildlog_path: "./fastlanelog",
codesigning_identity: "iPhone Developer: xxx (xxxxxxxxxx)",
output_directory: "/Users/xxx/Desktop"
)
#批量处理
desc "build all version ipa"
lane :all do |op|
t = op[:version]
ceshi version:t
release version:t
end
<code>最后,只需在终端(相关项目目录下)轻轻敲入:</code>
fastlane ceshi version:1.0.0 build:1.0.1 // 打包ceshi环境ipa,app版本号为1.0.0,build为1.0.1
fastlane release version:1.0.0 build:1.0.1 //打包App Store版本ipa,app版本号为1.0.0,build为1.0.1
fastlane all version:1.0.0 build:1.0.1 // 打包ceshi、App Store版本ipa,app版本号为1.0.0,build为1.0.1
<code>我们可以在 Fastfile 文件中添加一个函数来设置version号和build号,使得以上AppStore版本与Development版本配置使用同一函数,如下:</code>
default_platform :ios
def prepare_version(options)
increment_version_number(
version_number: options[:version]
)
increment_build_number(
build_number: options[:build]
然后可以在一个lane中使用这个函数:
lane :appstore do |options|
···
prepare_version(options)
然后执行这个lane
$ fastlane appstore version:2.4.0 build:2.0
调研ios-fastlane的安全性
调研fastlane在其他公司的使用情况
ios-fastlane踩坑篇
ios-fastlane问题篇