一、fastlane简介
fastlane是一套使用Ruby写的自动化工具集,用于iOS和Android的自动化打包、发布等工作,可以节省大量的时间。
fastlane官网:
https://fastlane.tools/
fastlane的官方Github:
https://github.com/fastlane/fastlane
fastlane文档说明:
https://docs.fastlane.tools/
使用fastlane前,确保你已经可以使用Xcode手动打包成功(说明你已经配置好证书)
1. 配置环境
1.安装HomeBrew
# 查看电脑有没有安装 HomeBrew 没有的话进行下面的安装
brew -v
#安装
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
#更新到最新版
brew update
#更新包
brew upgrade
2.安装ruby
# 查看电脑是否已经安装ruby 没有的话进行下面的安装
ruby -v
#安装
brew install ruby
#查看版本
ruby -v
# 例如我的电脑的ruby版本为
# ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin17]
3.安装fastlane
确保你的电脑上已安装最新版本的Xcode命令行工具(Xcode command line tools)
xcode-select --install
如果没有安装,会弹出对话框,点击安装。如果提示
xcode-select: error: command line tools are already installed, use "Software Update" to install updates
表示已经安装
开始安装fastlane
#安装
gem install fastlane -NV
或者使用
brew cask install fastlane
安装完之后
# 确认下是否安装完成和当前使用的版本号
fastlane -v
# 我的目前电脑版本
# fastlane installation at path:/Users/hf/.rvm/gems/ruby-2.2.3/gems/fastlane-2.108.0/bin/fastlane
# -----------------------------
# [✔]
# fastlane 2.108.0
二、使用fastlane
创建一个测试demo,我创建的是HFMyTest
我的项目的bundle id为www.hf.mytest
,这个bundle id需要在开发者中注册provisioning profile
同时注意设置scheme
为Shared
,不然fastlane init
的时候会失败,一般默认是选择Shared
的,可以不用去管
设置方法为:A、打开项目的Manage Schemes
B、勾选上
Shared
- 先cd到项目路径
cd /Users/hf/MyTest/HFMyTest/Example
- 初始化fastlane
fastlane init
可以看见有四个选项
- 自动化截图
- 将测试版分发自动化到TestFlight
- 自动上传、发布到App Store
- 手动设置 - 手动设置您的项目以使您的任务自动化
3. 我这里选择的是3
-
可能需要你去
select scheme
,注意这里面的sheme
不是你的项目名,例如我的项目名为HFMyTest
,sheme
就是上面介绍的勾选的Manage Shemes
中HFMyTest-Example
,所以这里选择1
由于选择3是要发布都AppStore,所以接下来输入用户的app id,这个id应该是具有开发者资格的账号
输入id之后接下来输入id的密码
-
输入账号和密码后
如果开发者账号上没有对应的bundle id的App,会提示是否创建一个新的App,这里我们选择否(n),因为这样快速创建的App设置的信息有限
-
接下来等待加载,按照步骤回车就可以完成初始化
-
初始化完成后,打开项目目录
发现项目中多出了fastlane目录,通过sublime或者文本编辑打开Appfile和Fastfile
app_identifier("www.hf.mytest") # The bundle identifier of your app
apple_id("[email protected]") # Your Apple email address
itc_team_id("118090429") # App Store Connect Team ID
team_id("MQJL2427R9") # Developer Portal Team ID
# For more information about the Appfile, see:
# https://docs.fastlane.tools/advanced/#appfile
- 上面这个Appfile默认已经初始化好了,不用再去操作
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:iOS)
platform :iOS do
desc "Push a new release build to the App Store"
lane :release do
increment_build_number(xcodeproj: "HFMyTest.xcodeproj")
build_app(workspace: "HFMyTest.xcworkspace", scheme: "HFMyTest-Example")
upload_to_app_store(skip_metadata: true, skip_screenshots: true)
end
end
- 以上Fastfile代码中,默认已经设置为上传到AppStore的操作
release为lane的名字,在执行lane的时候会用到,你可以为lane取任意的名字,也就是release可以取其它的,如appRelease
build_app用来编译app,你可以为其指定更多的的参数
打开终端cd到项目目录,运行就可以打包发布到
AppStore
使用以下命令来执行这个lane:
cd /Users/hf/MyTest/HFMyTest/Example
fastlane release
由于上面我们选择了否(n),也就是现在AppStore上面还没有我们这个HFMyTest
这个app,所以上面的操作会最终失败的
- 但是这时候打开
HFMyTest
本地目录会发现里面会有打出的ipa包
可能出现的问题
[10:00:00]: Installing dependencies for you...
[10:00:00]: $ bundle update
bundle update
过程太慢,可能又是被墙掉了。
关闭终端,打开项目文件夹,找到fastlane init
过程中生成的Gemfile
文件,并打开:
source "https://rubygems.org"
gem "fastlane"
修改为:
source "https://gems.ruby-china.com"
gem "fastlane"
然后打开终端,cd
到当前项目,再输入bundle update
到此
fastlane init
成功了,会出现在目录下出现了
Gemfile.lock
文件和
Fastfile
文件。
三、自定义Fastfile
我们知道上面的Fastfile是我们在fastlane init
初始化时4个选择中选择了3发布到AppStore,所以生成的Fastfile的功能是只具有发布到AppStore的功能
打开本地的HFMyTest目录
删除下面三个文件
然后重新运行一次初始化
cd /Users/hf/MyTest/HFMyTest/Example
fastlane init
然后在四个选项中选择第二个
然后按照开始的步骤来,最终的到的Fastfie如下
default_platform(:iOS)
platform :iOS do
desc "Push a new beta build to TestFlight"
lane :beta do
increment_build_number(xcodeproj: "HFMyTest.xcodeproj")
build_app(workspace: "HFMyTest.xcworkspace", scheme: "HFMyTest-Example")
upload_to_testflight
end
end
这个Fastfile主要是用于发布到TestFlight进行测试的,
所以我们可以再终端运行
fastlane beta
进行发布到testflight,和上面的一样,AppStore是上面没有创建对应的app,这个运行最终会失败。
Fastfile自定义,它的格式如下
···
# 自动更新fastlane 工具
# update_fastlane
#需要的fastlane的最小版本,在每次执行之后会检查是否有新版本,如果有会在最后末尾追加新版本提醒
fastlane_version "2.100.0"
#默认使用平台是 ios,也就是说文件可以定义多个平台
default_platform :iOS
platform :iOS do
before_all do
# ENV["SLACK_URL"] = "https://hooks.slack.com/services/..."
end
desc "Runs all the tests"
lane :test do
scan
end
desc "提交一个新的Beta版本到 Apple TestFlight"
desc "This will also make sure the profile is up to date"
lane :beta do
# match(type: "appstore") # more information: https://codesigning.guide
gym(scheme: "app_ scheme") # Build your app - more options available
pilot
# sh "your_script.sh"
end
desc "部署一个新版本到App Store"
lane :release do
# match(type: "appstore")
# snapshot
gym(scheme: "app_ scheme") # Build your app - more options available
deliver(force: true)
# frameit
end
# 你可以定义自己的lane
#执行lane成功后的回调
after_all do |lane|
# slack(
# message: "Successfully deployed new App Update."
# )
end
# 如果流程发生异常会走这里并终止
error do |lane, exception|
# slack(
# message: exception.message,
# success: false
# )
end
end
fastlane主要的操作就是action,常用的action有
scan
release情况下无法正常运行scan,需要手动去Build Setting中更改enable Testability 在release 下的状态,改为 yes才可以运行。但是官方不建议做release下开启,Test一般在development configuration 下执行。
gym
常用参数:
scheme :指定打的哪个scheme
project :指定project (未使用cocopods)
workspace :指定workspace (使用cocopods)
clean :打包前clean
xcargs : 附加一些参数传递给xcodebuild 如: xcargs: 'DEBUG_INFORMATION_FORMAT="dwarf-with-dsym"',
export_method :出包方法 app-store, ad-hoc, package, enterprise, development
configuration : 指定构建App的配置 Release、Debug、自定义
output_directory : 输出目录
output_name :输出名称
include_symbols :是否包含调试符号
include_bitcode :是否开启bitcode
pilot
#用于发布**testflight**内部测试,属于**testflight action**的别名
#常用参数:
#ipa :要提交的包地址
#team_name、team_id :如果有多个team 用于区分team
#skip_waiting_for_build_processing : 在提交完成后的等待是否跳过,一般跳过changelog
pilot(
ipa : '../xx.ipa'
)
deliver
#用于**直接发包到appstore**,可以选择跳过图片和元数据上传,只提包,后面再配图和数据:如下 skip_screenshots 和 skip_metadata 参数
deliver(
ipa: "#{OUTPUT_DIRECTORY}" + "/" + "#{IPA_NAME}",
skip_screenshots: true,
skip_metadata: true
)
四、插件的使用
- 查看所支持的插件
fastlane search_plugins
- 查看某种插件
fastlane search_plugins [query] #query为插件名
- 添加插件
fastlane add_plugin [name] #name 为插件名
- 插件使用实例:上传ipa包至蒲公英pyger
首先添加pyger插件:
# cd 到项目目录
cd /Users/hf/MyTest/HFMyTest/Example
# 安装插件
fastlane add_plugin pyger
#或者添加fir插件 fastlane add_plugin firim 上传到fir平台
编辑FastFile,添加以下信息
desc "打包并上传测试版至蒲公英"
lane :beta_pgyer do
#编译并导出ipa包
gym(
clean: true,
scheme: "scheme_name",
export_method: "development",
)
#上传至蒲公英
pgyer(
api_key: "",
user_key: "",
)
end
然后终端输入
fastlane beta_pgyer
就可以上传包到蒲公英
其中蒲公英的api_key和user_key需要用户去注册蒲公英账号,然后去获取
在Fastfile中可以自定义一个有外部传进来参数的方法options
,这个options类似于一个字典,可以传入不同的key来获取value,例如通过options[:myKey] 就可以获取value
lane :myTest do |options|
myTestStr = options[:key1]
end
传入options的值
fastlane myTest key1:myValue1 key2:myValue2
# 传入了两个数字
{"key1": myValue1,"key2":"myValue2"},
# 获取数值方式为
options[:key1] = myvalue1
在Fastfile中设置了increment_build_number
进行自动build数字增加,作用是防止本地版本的build号比App Store(或上次)低而做的自动增长版本号的处理,需要先在Xcode中配置如下
下面给出我的一套写好的Fastfile
注意:app_scheme
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
################## READ FIRST ##################
######## 使用方法1 自定义version和build #########
###### fastlane iosDebug version:1.0.1 build:1 ######
######## 使用方法2 不写version和build 这时build会根据之前的build+1 #########
###### fastlane iosDebug ######
###如果需要上传到蒲公英,请运行前先安装插件安装蒲公英的fastlane add_plugin pgyer ###
default_platform(:iOS) # 设置默认的平台为iOS
############# 需要根据项目自定义设置 ############
APP_NAME = "HFMyTest" #输出包时app的名字
APP_SCHEME = "HFMyTest-Example" #这个app打开manage schemes下选中的名称
APP_IPA_OUTPUT_DIRECTORY = "build/packages" # 打包所保存的文件目录,可以不设置
# 配置蒲公英的apiKey 和 userKey 需要设置
APP_PGYER_API_KEY = ""
APP_PGYER_USER_KEY = ""
# 配置fir的token
APP_FIR_API_TOKEN = ""
######## 不用设置的 #####################
APP_XCODEPROJ = "#{APP_NAME}.xcodeproj" # app的xcodeproj
APP_WORKSPACE = "#{APP_NAME}.xcworkspace" # app的xcworkspace
APP_IPA_TIME = Time.now.strftime("%Y-%m-%d_%H:%M") # 打包的时间
# APP_INFO_PLIST_PATH = './HFMyTest/HFMyTest-Info.plist'
APP_ENV_PREFIX = "" # 打包完成后的包文件名字的前缀 区别release和debug
# 版本 build number++
def prepare_version(options)
#增加version版本号
if options[:version]
increment_version_number(
version_number: options[:version],
xcodeproj: "#{APP_XCODEPROJ}",
)
else
# 可以不设置
end
#增加build号 只能是整数和浮点数
if options[:build]
increment_build_number(
build_number: options[:build],
xcodeproj: "#{APP_XCODEPROJ}",
)
else
last_build = get_build_number(xcodeproj: "#{APP_XCODEPROJ}")
now_build = last_build.to_i + 1
increment_build_number(
build_number: now_build,
xcodeproj: "#{APP_XCODEPROJ}",
)
end
end
#统一的打包方法
def generate_ipa(exportMethod,configuration,options)
# 设置version和build
prepare_version(options)
# 得到最新的version
app_version = get_version_number(target: "#{APP_SCHEME}")
# 最新的build
app_build = get_build_number(xcodeproj: "#{APP_XCODEPROJ}")
# app包名
app_ipa_name = "#{APP_NAME}_" "#{APP_ENV_PREFIX}" + "#{APP_IPA_TIME}_" + "#{app_version}_" + "#{app_build}"
#打包
gym(
clean: true, # 打包前clean项目
silent: true, # 隐藏没有必要的信息
scheme: "#{APP_SCHEME}",
workspace: "#{APP_WORKSPACE}",
configuration: "#{configuration}", # 环境
export_method: "#{exportMethod}", # app-store、ad-hoc、development、enterprise
output_directory: "#{APP_IPA_OUTPUT_DIRECTORY}", #ipa的存放目录
output_name: "#{app_ipa_name}", # 输出ipa的文件名
# 生成的ipa文件是否包含symbols,这个文件是内存标记文件,用来定位错误信息的,有了这个安装包大小会变大
include_symbols: true,
# 生成的ipa文件是否包含bitcode,在本身项目中也可以配置
include_bitcode: false,
# keychain授权 Xcode9不允许访问钥匙串密码,所以我们需要手动开权限
export_xcargs: "-allowProvisioningUpdates"
)
end
platform :iOS do
# before_all就是先于所有lane执行的任务
before_all do
# 根据安装路径指定要使用的Xcode
xcode_select "/Applications/Xcode.app"
# 超时失败,默认的timeout是10秒
ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "120"
# Appfile设置了可以忽略下面的证书设置
# 这个action很重要cert就是下载和安装匹配的Provision Profile文件,不用你去管那些证书不匹配的事情了
# cert(
# Appfile设置了这边就可以不用了
# username: "[email protected]",
# team_id: "xxxxxxx",
# output_path:"#{APP_CERT_OUTPUT_DIRECTORY}"
# )
#这一步就是签名了
# sigh(
# Appfile设置了这边就可以不用了
# app_identifier: ENV["APP_IDENTIFIER"],
# team_id: ENV['TEAM_ID'],
# 更新开发证书而不是生产证书
# development: ???
# 因为是根据BundleID下载,导致adhoc和appstore会优先appstore,导致最后导出报错,如果是adhoc包请设置为true
# adhoc: true,
# 设置所生成描述文件的名称,必须包含文件类型后缀.mobileprovision 可以不设置
# filename: "MyTest.mobileprovision",
# force:true,
# provisioning_name: 'MyTest AppStore',
# ignore_profiles_with_different_name: true,
# output_path: "build/sign",
# )
end
# lane 自定义的任务
#debug包 上传到蒲公英平台
#option类似一个字典 option[:version] 取其中value值version
lane :iosDebug_pgy do |options|
APP_ENV_PREFIX = "debug_"
generate_ipa("development","Debug",options)
#上传至蒲公英 在这之前请安装插件 fastlane add_plugin pgyer
if APP_PGYER_API_KEY.length > 0 && APP_PGYER_USER_KEY.length > 0
pgyer(
api_key: "#{APP_PGYER_API_KEY}",
user_key: "#{APP_PGYER_USER_KEY}",
)
notification(title: "发布成功!", message: "已成功上传到蒲公英平台, 赶快联系测试人员开始测试吧!", open: "https://www.pgyer.com/")
end
end
#debug包 上传到fir
lane :iosDebug_fir do |options|
APP_ENV_PREFIX = "debug_"
generate_ipa("development","Debug",options)
#上传至fir 在这之前请安装插件 fastlane add_plugin firim
if APP_FIR_API_TOKEN.length > 0
firim(
firim_api_token: "#{APP_FIR_API_TOKEN}",
)
notification(title: "发布成功!", message: "已成功上传到fir平台, 赶快联系测试人员开始测试吧!", open: "https://fir.im/apps")
end
end
# release发布包
lane :iosRelease do |options|
APP_ENV_PREFIX = "appstore_"
generate_ipa("app-store","Release",options)
# 上传至app-store
deliver(
force: true, #是否跳过HTML验证报告,默认false
skip_metadata: true, #是否跳过上传metadata,默认false
skip_screenshots: true #是否跳过上传屏幕截图,默认false
)
notification(title: "发布成功!", message: "已成功发布到appstore, 请查验!", open: "https://itunesconnect.apple.com")
end
# testFlight包
lane :iosTestFlight do |options|
APP_ENV_PREFIX = "adhoc_"
generate_ipa("ad-hoc","Release",options)
# 管理TestFlight的测试用户,上传二进制文件
pilot
notification(title: "发布成功!", message: "已成功发布到appstore, 请查验!", open: "https://itunesconnect.apple.com")
end
# 当lane执行完成之后进行哪些操作
after_all do |lane|
#发送一个桌面通知
#notification(title: "execute success", subtitle: "执行成功!", message: "lane已经执行成功了")
end
error do |lane, exception|
puts("#{exception.message}")
notification(title: "执行#{lane}发生异常!", message: "发生异常, 详情请查看控制台!")
end
end