iOS 持续交付之 Fastlane

2018阿里云全部产品优惠券(好东东,强烈推荐)
领取地址https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=gh9qh5ki&utm_source=gh9qh5ki

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

[fastlane 是一个通过简单命令来完成诸如截图、获取证书、编译、导出安装包、提交iTunesConnect等一系列操作的工具,它同时支持iOS和Android。 你能够通过简单的方式配置流

小目标:使用Jenkins一键构建,并自动上传到App Store。

一、为什么选择 Fastlane

fastlane是为iOS和Android应用程序自动化测试部署和发布的最简单方法。它处理所有繁琐的任务,如生成屏幕截图,处理代码签名以及发布应用程序。

使用场景

  • 提交时执行测试(包括单元测试和集成测试)。

  • 构建并分发内部测试,公开测试版本。

  • 构建生产版本并上传至 ITC(包括更新配置文件,创建新的屏幕截图,上传应用并提交审核)。

工具集

fastlane将如下的工具套件有机地结合起来,从管理证书到单元测试,从编译打包到上传发布,都能通过命令行轻松完成.该套件支持与Jenkins和CocoaPods,xctools等其他第三方工具的集成,并且能够定义多个通道(lanes)以支持不同的部署目标。

  • 测试工具

    • scan:自动运行测试工具,可以生成漂亮的HTML报告。

  • 生成证书、配置工具

    • cert:自动创建iOS代码签名证书(.cert文件)。

    • sigh: 创建、更新、下载和修复 provisioning profiles,支持App Store, Ad Hoc, Development和企业profiles。

    • pem:自动生成、更新推送配置文件。

  • 截图、上传、描设备边框

    • deliver: 上传截图、元数据、App到iTunesConnect。

    • snapshot: 依靠 UI Test 完成截图。

    • frameit: 快速地把应用截图放入设备框里。

  • 自动化编译工具

    • gym: 编译、打包iOS app,生成签名的ipa文件 。

  • App 公测工具

    • pilot:管理TestFlight测试用户,上传二进制文件。

    • firim:管理firim。

二、准备工作,很重要的哟

  1. 配置当前设备环境,最新的fastlane(2.75.1)需要2.1以上的ruby版本,正常的版本低点的,也是要求2.0以上的。因为fastlane工具是使用ruby写的。版本过低的建议安装 rvm 来升级ruby。

    curl -L get.rvm.io | bash -s stable
    
    source ~/.bashrc
    source ~/.bash_profile 
    
    # 检测是否安装成功
    rvm -v
  2. 设置环境变量,fastlane需要设置一些环境变量才能正确运行,如果当前的语言环境没有设置为UTF-8,会导致构建和上传的时候出现问题。在~/.bashrc,~/.bash_profile或者~/.zshrc文件下添加如下内容:

    export LC_ALL=en_US.UTF-8 
    export.UTF-8
  3. 安装Xcode命令行工具xcode-select --install,如果已经安装会提示xcode-select: error: command line tools are already installed, use "Software Update" to install updates。

  4. 创建App ID,证书,在iTunes connect创建一个用于测试的 app。

  5. 安装fastlane

  6. 创建一个测试demo。

    1. 并将其scheme设置为shared,不然fastlane init的时候会失败。

    2. 设置好签名配置文件。

    3. 为app添加icon。

    4. 修改devices为iPad或者iPhone。

三、实践

fastlane init

  1. cd 到项目目录下,对于ruby安装程序,使用命令sudo fastlane init。(swift使用fastlane init swift, Swift安装仍在测试阶段。有关更多信息,请参阅 Fastlane.swift 文档。 )

  2. 会问你想使用fastlane做什么?这里我们输入3,自动发布到Apple Store。

    执行过程中会要求你输入Apple开发证书的Apple ID,如果有多个Team,会让你选择team。

  3. 接着会问是否想用fastlane来管理你的app metadata。

    • 输入y,fastlane则会下载现有的元数据和屏幕截图。如果我们编辑了download下来的.txt文件,在使用fastlane上传app到iTunes connect的时候也会将这些内容上传到iTunes connect。

    • 输入n,不做任何操作,仍然能使用fastlane上传app到App Store。

  4. 如果最后出现fastlane release,就表示init成功了。

  5. 此时项目目录下会多出一个fastlane的文件夹。

    如果Deliverfile,screenshots和metadata目录没被创建,可以运行deliver init来创建。

在Deliverfile文件里,添加force true,不然会在上传到iTunes connect的时候会弹出一个Preview.html网页。

使用Gemfile

  1. 在项目根目录下touch一个Gemfile文件,添加以下内容

    推荐:iOS可持续化集成: Jenkins + bundler + cocoapods + shenzhen + fastlane + pgyer

    [工具介绍1. bundlerbundler用于管理ruby gem的工具,我们用来管理cocoapods以及fastlane的版本号。直接sudo gem install bundler即可。然后在工程的根目录下,添加Gemfile

    source "https://rubygems.org" 
    gem "fastlane"
  2. 执行如下命令:

    # 安装bundler
    sudo gem install bundler
    
    # 更新 bundle,成功之后会生成一个版本控制的Gemfile.lock文件
    [sudo] bundle update
  3. 执行命令:bundle exec fastlane [lane_name],执行lane_name脚本。这里的lane_name是脚本的名称,我们可以理解为函数名,如果我们只执行bundle exec fastlane命令,则会有一个让我们选择的地方,选择需要执行的脚本。

    会将项目名,ipa存放的路径,app_identifier等一系列信息打印出来。

    ipa和dYSM文件都存放在项目根目录。

    紧接着会自动上传metadata和ipa到iTunes Connect。

    最后会输出每个脚本执行所消耗的时间(s)。

进阶

如果只是很简单的上传到iTunes connect,上面的操作就可以满足。

如果我们是多个target或者需要配置一些ITC上面的内容,则需要进一步的深入。

metadata

metadata是包含应用在ITC上面的各种信息,可以使用它配置我们的ITC,建议使用Deliverfile。

screenshots

屏幕截图数据。

Appfile

存储App信息,比如Apple ID,bundle ID等信息。

Deliverfile

交付文件。在这个文件里面可以设置iTunes connect的所有配置项,例如:

  • release_notes,此版本新增内容。

  • copyright,版权信息。

  • submit_for_review,上传完成后是否直接提交新版本进行审查。

  • force,跳过HTML报告文件验证。

  • ...

请在设置release_nores、support_url、private_url等配置的时候,采用hash的方式写, 国家代码 ,例如:

release_notes(
	# 中国
	'zh-Hans' => ENV['RELEASE_NOTES'],
	# 澳大利亚
	'en-au' => ENV['RELEASE_NOTES_AU'],
	# 美国
	'en-us' => ENV['RELEASE_NOTES_US']
)

Fastfile

自动化脚本配置文件。 是我们脚本的入口,所有的事件驱动都是在这个文件来调度的。

default_platform(:ios)
platform :ios do
	desc "demo upload_to_app_store"
	lane : Archive_TargetA do |options|
		scheme = options[:scheme]
		date = Time.new.strftime("%Y%m%d-%h%M")
		
		# export_method 支持 app-store, ad-hoc, package, enterprise, development
		gym(
			scheme: "#{scheme}",
			output_name: "#{scheme}-#{date}.ipa",
			clean: true,
			export_method: 'app-store',
		)
		# upload_to_app_store
		deliver # 当deliverfile为空的时候,同 upload_to_app_store 作用一样
	end
end

cd到项目根目录执行命令:bundle exec fastlane Archive_TargetA scheme:"CDDemo",后面的scheme是带的参数。

Multi-Target

如果我们需要配置多个target进行打包的话,我们可以使用 环境变量 ,来进行配置。假如我们现在有两个target,targetA和targetB,则我们需要创建两个.env文件,例如.env.targetA,.env.targetB,放在Fastfile文件同级目录下

在.env文件里面我们可以配置一些不同的内容(非公共),比如app_identifier,release_notes等等。截图如下:

在Appfile,Deliverfile,Fastfile等文件,我们都可以直接使用.env文件里面的内容。

Appfile

# Appfile
#The bundle identifier of your app
app_identifier ENV['APP_IDENTIFIER']
# Your Apple email address
apple_id ENV['APPLE_ID'] 
# Developer Portal Team ID
team_id ENV['TEAM_ID']

Deliverfile, 请在设置release_nores、support_url、private_url等配置的时候,采用hash的方式写。

# app_identifier
app_identifier ENV['APP_IDENTIFIER']
# 用户名,Apple ID电子邮件地址
username ENV['APPLE_ID']
# 团队ID
team_id ENV['TEAM_ID']
# 团队name
team_name ENV['TEAM_NAME']
# copyright
copyright ENV['COPYRIGHT']
# 关键字
keywords(
	'zh-Hans' => ENV['KEYWORDS'],
)
# 新版本修改记录
release_notes(
	# 中国
	'zh-Hans' => ENV['RELEASE_NOTES'],
	# 澳大利亚
	'en-au' => ENV['RELEASE_NOTES_AU'],
	# 美国
	'en-us' => ENV['RELEASE_NOTES_US']
)
# 支持网址
support_url(
	# 中国
	'zh-Hans' => ENV['SUPPORT_URL'],
	# 澳大利亚
	'en-au' => ENV['SUPPORT_URL_AU'],
	# 美国
	'en-us' => ENV['SUPPORT_URL_US']
)
# 隐私政策网址 国家代码 https://www.cnblogs.com/Mien/archive/2008/08/22/1273950.html
privacy_url(
	# 中国
	'zh-Hans' => ENV['PRIVACY_URL'],
	# 澳大利亚
	'en-au' => ENV['PRIVACY_URL_AU'],
	# 美国
	'en-us' => ENV['PRIVACY_URL_US']
)
# 上传完成后提交新版本进行审查
submit_for_review false
# 跳过HTML报告文件验证
force true
# 启用iTC的分阶段发布功能 灰度发布
phased_release true
# 应用审核小组的联系信息 app 审核信息
app_review_information(
  first_name: "xx",
  last_name: "xx",
  phone_number: "+86 18888888888",
  email_address: "xxxx",
  demo_user: "test1@test.com",
  demo_password: "test123"
)
...

Fastfile文件里面使用环境变量,跟上面略有不同。在Fastfile里面,我们需要告诉lane要使用那个.env文件,这时候我们需要使用sh脚本命令的形式来调用一个lane 后面跟上--env 环境变量文件名,此时调用的lane不能声明为private_lane,调用方式如下:

lane :releaseDemo2 do
	# 无参数
	sh "fastlane Archive_TargetA --env TargetA"
	
	# 有参数
	sh 'fastlane Archive_TargetA type:\'哈哈哈哈\' --env TargetA'
end
外部直接调用(带参数)
bundle exec fastlane Archive_TargetA type:"haha" --env TargetA

然后我们在Archive_TargetAlane 里面使用ENV['xx']方式,读取出来的内容就是从.env.TargetA文件读取出来的。同理,deliverAction 对应的DeliverFile文件里面的内容也是从.env.TargetA文件读取出来的。

private_lane : Archive_TargetA do |options|
	scheme = ENV['SCHEME'] # 这时候读取出来的'scheme'就是'TargetA',从'.env.TargetA'读取出来的
	# export_method 支持 app-store, ad-hoc, package, enterprise, development
	gym(
		scheme: "#{scheme}",
		output_name: "#{scheme}.ipa",
		clean: true,
		export_method: 'app-store',
	)
	deliver # 这时候deliverfile里面读取的内容就是从'.env.TargetA'文件读取的
end

lane之间的调用

跟我们自己写方法调用一样,例如:

desc "打包统一入口"
lane :Archive do |options|
	# 如果我们传入的参数'type'是targetA,那么我们就执行Archive_TargetA 这个lane。。。
	type = options[:type]
  	if type == "TargetA"
    	Archive_TargetA(options)
  	elsif type == "TargetB"
        Archive_TargetB(options)
	else
    	Archive_TargetA(options)
  	end
end

系统级lane

fastlane默认有 lane。

  • before_all,就是在执行一次脚本之前首先执行的代码,我们可以在这里面执行一些公共的东西,比如git_pull,cocoapods。

    before_all do
      # 检出到 Developer 分支
      sh 'git checkout Developer'
      git_pull
      cocoapods(repo_update: true)
    end
  • after_all, 成功结束之后,处理共有的后置逻辑。

  • before_each,每次执行 lane 之前都会执行一次。

  • after_each,每次执行 lane 之后都会执行一次。

  • error,在执行上述情况任意环境报错都会中止并执行一次。

执行顺序

执行顺序 方法名 说明
1 before_all 在执行 lane 之前只执行一次。
2 before_each 每次执行 lane 之前都会执行一次。
3 lane 自定义的任务。
4 after_each 每次执行 lane 之后都会执行一次。
5 after_all 在执行 lane 成功结束之后执行一次。
6 error 在执行上述情况任意环境报错都会中止并执行一次。

Error

  • 出现Command timed out after 10 seconds on try 1 of 4, trying again...,在fastlane文件开头加上:

    ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "180" 
    ENV["FASTLANE_XCODE_LIST_TIMEOUT"] = "180"

插件

  • versioning ,用来修改build版本号和version版本号。Fastlane内嵌的actionincrement_build_number使用的是苹果提供的agvtool,agvtool在更改Build的时候会改变所有target的版本号。这时如果你在一个工程里有多个产品的话,每次编译,所有的Build都要加1,最后就不知道高到哪里去了。fversioning不仅可以指定target增加Build,而且可以按照「语义化版本」规范增加Version,当然也可以直接设定Version。

  • firim,直接把AdHoc或者InHouse打包的ipa上传到fir.im,供测试下载。

自定义插件

插件安装格式

fastlane add_plugin [name],需要到项目根目录下执行。

fastlane update_plugins插件更新,同上,需要cd到项目根目录下。

注意

  • 保持打包机器的Xcode 和 证书是最新的。

  • 使用脚本命令形式调用的时候不能设置成private_lane。

  • private_lane表示私有lane,使用bundle exec fastlane命令,声明为private_lane的是不是显示出来的,使用脚本命令形式调用的时候不能设置成private_lane。

其它

可以直接在lane里面执行git命令,例如sh 'git checkout Developer',检出Developer分支。

由于本人的水平有限,难免会有错误和疏漏,也欢迎各位同学指正,如果大家在Fastlane的使用上,有更好的案例,也欢迎交流和分享。

Demo

CDDemo

推荐:以主干开发作为持续交付的基础

[看新闻很累?看技术新闻更累?试试 下载InfoQ手机客户端 ,每天上下班路上听新闻,有趣还有料! 早在他们的重要著作《 持续交付 》一书于2011年发布之前, Dave Farley 和

在线网页数据采集器

相关推荐