「文章标题虽然说是小团队的自动发布工具,但是这篇文章适合只要你们公司还没有自动化发布流程。」
作为公司的iOS程序员,少不了在发布应用的时候各种等待。标准的手动发布流程是:编译->打包上传->填写应用更新数据->等待iTunesConnect编译->选择版本发布,整个过程大概需要30分钟左右。关键是这个过程就像windows装系统一样,虽然手工参与的不多,但是要一直守在电脑前等着。
程序员这么懒,一定会想办法让他自动化的。后来发现特别懒的Felix Krause写的Fastlane,Fastlane可以非常快速简单的搭建一个自动化发布服务,并且支持Android
,iOS
,MacOS
。他可以实现一条命令从编译到选版发布全程不用干预。作为程序员的你只要一条命令,看集美剧,发布就完成了。截止刚刚Fastlane官网上宣称已经为程序员节省了4百万小时+
这是一篇中速入门,看完这篇文章,自己搭建个「iOS自动发布服务」肯定是没问题了。这篇文章很长,有很多细节,可以当文档查。
文章难度:★☆☆☆☆
系统要求
- 会编程
- Xcode7+
- Mac OS 10.11+
Fastlane组件
Fastlane是一套工具集,包括:
- 测试
- scan => 自动运行测试工具,并且可以生成漂亮的HTML报告
- 证书,配置文件
- 截图
- 编译
- shenzhen => 当年大名鼎鼎的自动编译工具,现在已经被弃用了
- gym => Fastlane家族的自动化编译工具,和其他工具配合的非常默契
- 发布
TestFlight
管理- 辅助工具
- spaceship => 为
pilot
,boarding
和deliver
等工具提供和 iTC 和 ADC 的交互API。spaceship
本来是个独立的项目,后来被Fastlane
收编进来 - WatchBuild => 是一个独立的iTC监控工具,开启
WatchBuild
可以监控iTC上的文件状态,弹出MacOS自带的Notification
- spaceship => 为
- Android
- supply => 自动上传到Google Play工具(如果有时间,我想把国内提供API的Android Store都写个插件自动上传,这个问题从10年我刚开始工作就觉得是个痛点)
- screengrab => Android的自动截图工具
Fastlane中的概念
fastlane命令是一个流程控制的命令行工具(CLI),通过内部集成action
和第三方的action
完成一系列控制流程。运行fastlane命令行工具,会读取当前目录或者./fastlane
目录下的Fastfile
配置文件。
在Fastfile
中:
action
=> Fastlane中的每一条命令都是一个扩展(action),上面提到的deliver
,sigh
之类的工具本身是CLI,但是在Fastlane中内嵌了对他们支持的action
lane
=> Fastlane中流程的合集,每一个动作即可以是action
,也可以是其他的lane
。语法和ruby中的rake非常像
一个简单的发布流程:
|
|
安装
苹果的系统升级率非常高,所以现在绝大部分开发者电脑应该是满足依赖要求的。
确保Xcode Command Line Tools
安装了最新版
|
|
如果你单独安装过ruby(如果你能看得懂这句),去掉sudo
。如果使用系统自带的ruby,需要sudo
权限
|
|
- 如果在安装中速度过慢,请参照更改Gem镜像。
初始化
在项目根目录下,初始化Fastlane:
|
|
提问了你的Apple ID
,Team
的问题之后,fastlane会自动检测当前目录下项目的App Name
和App Identifier
。如果检测的不对,选择n
自行输入。
接下来会问你这个app是否需要在iTC和ADC中创建(上一步中如果选择y
会自动检测是否需要创建),fastlane会调用produce
进行初始化,如果现在还不想创建,也可以之后再运行produce init
进行这个流程。如果不执行produce
的流程,deliver
的流程也会被掠过,当然之后也可以deliver init
运行完全一样的流程。
在执行deliver init
的过程中,会同步iTC中的所有语言的元数据和截图,并按照目录结构组织好。目录结构应该类似下面:
|
|
这里肯定会被创建的是Appfile
和Fastfile
。如果Deliverfile
,screenshots
和metadata
目录没被创建,可以运行deliver init
来创建。
- Fastfile => 用来定义所有的lane任务Fastfile帮助
- Appfile => 是用来存储一些公共信息的,比如
app_identifier
,apple_id
,team_id
,itc_team_id
等。Appfile帮助 - Deliverfile =>
deliver
的配置文件Deliverfile帮助
PS:
- 这里有个小问题,iTC和ADC中的
Team ID
是不一样的,在fastlane init
中只会自动在Appfile里写入ADC的team_id
,所以在这个过程中会不停的问你iTC的Team ID
,所以在创建完Appfile后,手动在里面添加itc_team_id
。 - 这个问答对不同的项目可能有各种各样的分支。我已经用不同的项目试过很多次了,但是可能还不是全部,所以你还需要见招拆招。
- 在这里可以安心的输入密码,所有的密码都加密保存在系统的Keychain里。
插件
Fastlane的插件是一个或者一组action
的打包,单独发布在fastlane之外。Fastlane Plugin 指南
自从16年5月份推出插件系统以来,现在已经有很多第三方的插件可以使用。查看所有插件:
|
|
这里介绍两个下文会用到的插件:
fastlane-plugin-versioning => 用来修改build版本号和version版本号。
Fastlane内嵌的action
increment_build_number
使用的是苹果提供的agvtool
,agvtool
在更改Build的时候会改变所有target的版本号。这时如果你在一个工程里有多个产品的话,每次编译,所有的Build都要加1,最后就不知道高到哪里去了。有了
fastlane-plugin-versioning
不仅可以指定target增加Build,而且可以按照「语义化版本」规范增加Version,当然也可以直接设定Version。PS:最开始写iOS时不知道怎么定义Build。现在我一般都直接定义成纯数字,比如100起,每次编译的时候让他自动加一。
fastlane-plugin-firim => 直接把AdHoc或者InHouse打包的ipa上传到fir.im,供测试下载。
安装上面的插件
|
|
配置发布流程
可以把二进制发布到三个地方:
- 发布测试版到Fir.im
- 发布测试版到TestFlight (这个留到下篇文章写)
- 发布到Apple Store
发布到Fir.im
Lane
有了Fastfile
,就可以添加自己的发布流程了。打开Fastfile文件(这里我用Sublime 设定语法为Ruby),如果不出意外的话你生成的Fastfile和我应该差不多。这里我就不贴出来了。
最开始定义了
fastlane_version
=> 指定fastlane最小版本default_platform
=> 指定当前平台,可选ios,android,mac
在platform
中就是需要修改的重点。先忽略before_all
,after_all
,error
这些方法,这里的lane
就是一组任务,上传到Firim的任务如下
|
|
Sigh
如果你不确定证书目前是否可用,可以用Sigh自动生成获取证书。Sigh会自动根据Appfile里设置的app_identifier
从ADC(苹果开发者中心)生成证书,并下载到项目根目录下(不是fastlane目录),下载后自动安装。你可以通过指定output_path
指定证书下载位置。
PS:建议不要把这个文件夹同步到项目的git中(Fastlane提供了match
专门管理所有证书)。可以在.gitignore中可以忽略这个文件夹。
Sigh常用的配置项:
Name | Type | Description | Default |
---|---|---|---|
adhoc | bool | 获取adhoc证书 | fasle |
development | bool | 更新开发证书,不更新production 证书 |
false |
force | bool | 强制更新证书,不管证书是否在ADC中存在 | false |
iOS里code打包证书有4种,adhoc,inhouse,appstore,development证书。
价格 | AppStore证书 | In-House证书 | AdHoc证书 | Development证书 | |
---|---|---|---|---|---|
企业帐户 | $299 | √ | √ | √ | |
公司账号 | $99 | √ | √ | √ | |
个人账户 | $99 | √ | √ | √ |
其中In-House
的方式打包的ipa安装没有设备的限制。AdHoc
打包的ipa必须提前把设备的UDID添加到证书中,并且有100台设备限制。
所以如果你不指定adhoc
为true
,Sigh会识别帐户类型,企业帐户默认生成In-House
证书,公司账号和个人帐户默认生成AppStore证书。
Gym
Gym常用配置项:
Name | Type | Description | Default |
---|---|---|---|
scheme | string | 指定需要编译的scheme | |
clean | bool | 是否在编译前clean | false |
output_directory | string | 导出目录 | ./ |
output_name | string | 导出ipa名字 | [app_name].ipa |
export_options | hash/string | 这里指定Xcode API的外部配置文件地址,或者配置hash,见下文 | |
export_method | string | 打包方式,可选项app-store ad-hoc package enterprise development developer-id |
如果在fastlane中使用了sigh,这个值会从上下文获取 |
include_bitcode | bool | 是否开启bitcode |
Xcode API 默认值为true |
include_symbols | bool | 是否生成符号表 | Xcode API 默认值为true |
Xcode7之后,Xcode API允许我们指定一个plist
文件作为额外的配置文件。gym默认会帮你创建这个文件,你可以直接指定配置。更多关于plist可配置项,执行xcodebuild -help
查看Available keys for -exportOptionsPlist
。
export_method
, include_symbols
,和include_bitcode
这些参数都是exportOptionsPlist
的配置,对应method
,uploadSymbols
和uploadBitcode
。
Gym可以指定配置文件Gymfile
。 初始化:
|
|
Firim
Fir.im是一个ipa托管网站。你可以用AdHoc
或者In-House
的方式打包,上传到fir.im发送给测试人员测试。需要先注册Fir.im帐户,并生成Token
。这种方式适合:
- 小团队 => 测试的机器数量很少并且非常可控。直接连上开发机,真机调试一次,就可以添加
- 土豪 => 有企业帐户可以打
In-House
的包
Firim常用配置项:
Name | Type | Description | Default |
---|---|---|---|
firim_api_token | string | 指定fir.im的token |
|
ipa | string | ipa 地址 |
如果使用gym ,可以通过上下文获取 |
icon | string | icon的path,注意这里有个非常坑的地方,fir.im只支持jpg格式的图片 |
还有项如app_name
等等,是用来配置fir.im页面属性的。firim --help
Firim的配置文件是Firimfile
。初始化:
|
|
Firim
是我完全仿照fastlane组件的方式写的,所以也可以单独作为CLI
使用。
如果有任何Firim
的问题请到Firim的issues提问。
发布
配置完以上项,就可以一条命令发布到fir.im了:
|
|
发布到App Store
Lane
先看下lane
:
|
|
Deliver
Deliver可以完全管理与iTC的交互。其中包括:
- 上传和下载多语言截图
- 上传和下载多语言元数据
- 上传二进制文件
还记得上面初始化的时候初始化的metadata
,screenshots
目录么?iTC中的所有的元数据信息都被保存在metadata
中,所有的截图信息都被保存在screenshots
中。
metadata:
- 可以很容易的管理对应目录下的文件和iTC后台的表单项,在执行
deliver
时会自动被传到iTC。 - 在
metadata
目录下的文件,如copyright.txt
,是没有本地化的,在二层目录中的文件都是需要对应不同语言的表单项。 - 如果你不想修改某些项的信息,直接把对应的文件删除即可。
- 所有这些表单项也可以在
Deliverfile
中指定,Deliverfile
中指定的项优先级比文件高
screenshots:
- 如果不想更改截图,可以把整个截图目录删除
- 如果不使用
snapshot
(自动化截图),也可以自己截图放到对应目录下,比一张一张上传iTC快的多。截图在iTC中的排列顺序就是本地文件名的「字母表顺序」(在目录中右击,按文件名排序)。deliver
会识别图片分辨率,上传到对应设备中。
如果要通过deliver
修改元数据或截图,你必须提供所有iTC后台中有的语言。比如后台中有「简体中文」和「英文」,你也必须提供对应的zh-Hans
和en-US
文件,否则deliver
会报缺少语言的错误。可以在iTC后台提交的版本中删除语言。
Deliver常用配置项:
Name | Type | Description | Default |
---|---|---|---|
ipa | string | ipa 地址 |
如果使用gym ,可以通过上下文获取 |
metadata_path | string | 指定metadata 目录地址 |
如果在fastlane 中./fastlane/metadata ,如果作为独立的命令行应用./metadata |
screenshots_path | string | 指定screenshots 目录地址 |
如果在fastlane 中./fastlane/screenshots ,如果作为独立的命令行应用./screenshots |
skip_binary_upload | bool | 跳过二进制文件上传,适用于只想改metadata |
false |
skip_screenshots | bool | 跳过截图上传,如果截图没有变化,开启这项节约时间 | false |
skip_metadata | bool | 跳过元数据上传 | false |
force | bool | deliver 会在上传时汇总信息生成HTML也,等待你审核。跳过这项审核此项设为true |
false |
submit_for_review | bool | 上传完成是否自动提交审核 | false |
automatic_release | bool | 审核通过是否自动释放 | false |
price_tier | int | App价格级别。注意:这项提交当时就会生效,所以更改价格还是在后天手动操作 | |
submission_information | hash | 这是在iTC上点击提交之后的问答表格,可选项 | |
app_review_information | hash | 提供审核时的信息,详情 | |
app_icon | string | 指定icon 图片地址,必须为png 格式 |
submission_information =>
- 前缀
export_compliance
=> 对应「出口合规信息」,没有特殊情况都选false
就可以。 - 前缀
content_rights
=> 问你是否包含,显示,访问第三方内容(这项我没在我提交过程中找到),没有特殊情况也都选false
就可以。 前缀
add_id_info
=> 可就关键了,对应「广告标识符」,如果你在App中使用了IDFA
。你必须在这给个理由,而不能直接选false
。下图等价下表,App中投放了广告。
123456789101112131415161718submission_information({export_compliance_available_on_french_store: "false",export_compliance_contains_proprietary_cryptography: "false",export_compliance_contains_third_party_cryptography: "false",export_compliance_is_exempt: "false",export_compliance_uses_encryption: "false",export_compliance_app_type: nil,export_compliance_encryption_updated: "false",export_compliance_compliance_required: "false",export_compliance_platform: "ios",content_rights_contains_third_party_content: "false",content_rights_has_rights: "false",add_id_info_limits_tracking: "true",add_id_info_serves_ads: "true",add_id_info_tracks_action: "false",add_id_info_tracks_install: "false",add_id_info_uses_idfa: "true"});
- 前缀
deliver
的CLI
工具:
- 下载iTC上的截图
deliver download_screenshots
- 下载iTC上的元数据
deliver download_metadata
发布
配置后,还是一条命令:
|
|
后记
终于写了第二篇分享,第一篇还是3年前在知乎上的问答。这篇文章前后用业余时间改了一个星期,主要时间都放在验证各种情况,核实很多细节,尽量能把提到的说的详细。以前读一些入门文章,经常我的环境稍微不对,可能就跑不通了(当然,这篇也不可能覆盖所有情况)。所以最后也导致写的太长,而且有很多废话,希望大家谅解。
写文章真没有想象中容易。以前看别人写的文章,读可能只要10分钟,作者可能要写几个小时。感谢所有人的分享!
写文章是个好习惯。程序员的工作虽然辛苦,但是太单调安逸。有时感到很绝望,感觉生命就这样一直走到底,再也不会改变。我想逼自己一次,做点自己不喜欢或者不擅长的事。
这篇文章还没写完,因为太长,只能分成两部分。另一部分会讲下fastlane一些进阶用法,还有自动上传到TestFlight => pilot
,还有证书管理工具match
最后,谢谢大家的观看!