
背景
我們都知道將開發(fā)好的APP發(fā)布到AppStore的流程大概是:編譯->打包IPA上傳->填寫應(yīng)用更新數(shù)據(jù)->等待iTunesConnect編譯->選擇版本發(fā)布,整個過程大概需要30分鐘左右(前提是公司網(wǎng)絡(luò)還要好,說多了都是淚啊~), 悲催的是如果某一次Build Version忘記增加了,那這個流程還得再來一遍,對于經(jīng)常不斷迭代的產(chǎn)品,這更是痛啊~~
還有一種情況,發(fā)布一個Pod遠(yuǎn)程私有庫或者是Pod公開庫的流程大概是:
增加Podspec中的版本號->pod install -> Git Commit代碼->打標(biāo)簽Tag->推送Tag到Origin->執(zhí)行pod lib lint命令進(jìn)行庫驗證->執(zhí)行pod repo push命令發(fā)布庫到私有倉庫或者pod trunk push到CocoaPod公開庫中,整個過程雖然沒有任何技術(shù)含量,但是整個過程下來半個小時沒了,如果中間標(biāo)簽打錯了,或者是標(biāo)簽忘記推送到遠(yuǎn)端了,囧,整個過程還得再來一遍!!!
那么有沒有什么工具或者好的輪子可以解決上述問題呢?肯定是有的,下面我們就來聊聊今天的主角:Fastlane

fastlane 簡介
Fastlane 是一個完全開源的項目,是一款為 iOS 和Android 開發(fā)者提供的自動化構(gòu)建工具,它可以幫助開發(fā)者將 App 打包、簽名、測試、發(fā)布、信息整理、提交 App Store 等工作完整的連接起來,實現(xiàn)完全自動化的工作流,如果使用得當(dāng),可以顯著的提高開發(fā)者的開發(fā)效率。
下面是fastlane的GitHub的鏈接和官方地址;
fastlane 的使用
安裝前請確保你已經(jīng)安裝了最新的 Xcode command line tools,通過在終端中執(zhí)行下面的命令你可以進(jìn)行檢查。
xcode-select --install
安裝 fastlane
sudo gem install -n /usr/local/bin fastlane
查看版本

為項目配置fastlane
$ cd 項目根目錄
$ fastlane init
如果期間報錯 Connection reset by peer - SSL_Connect,就需要執(zhí)行:
$ brew update && brew install ruby
// 重裝
$ sudo gem install -n /usr/local/bin fastlane
然后重新執(zhí)行
$ fastlane init
在這期間會讓你輸入 Apple ID 賬號密碼,這個信息會存儲在鑰匙串中,后續(xù)使用無需再輸入密碼
會檢測當(dāng)前的 app identifier 是否在 Apple Dev Center 中
會檢測當(dāng)前 app 是否在 iTunes Connect 中
如果已經(jīng)在 ADC 和 ITC 中創(chuàng)建相應(yīng)的信息,那么過程會很順利,如下圖:

執(zhí)行完成之后會在項目目錄中生成如下文件結(jié)構(gòu):

上面這些文件中,最重要的兩個文件就是Appfile和Fastfile。
Appfile里面存放了App的基本信息包括App_Identifier、AppID、Team_ID。如果在init的時候你輸入了正確的AppID賬號和密碼會在這里生成正確的team_id信息。如果沒有team,這里就不會顯示。
Fastfile是最重要的一個文件,在這個文件里面可以編寫和定制我們打包腳本的一個文件,所有自定義的功能都寫在這里。
但是如果我們沒有在iTunes Connect中創(chuàng)建APP,那么就不會創(chuàng)建上述metadata和screenshots兩個文件夾;當(dāng)然我們也可以后續(xù)創(chuàng)建,執(zhí)行如下操作即可:
$ fastlane produce init
FastFile文件
接下來我們分析下這個文件:
#指定當(dāng)前fastlane使用的最小版本。
fastlane_version "2.50.0"
#指定當(dāng)前平臺,可以選擇iOS,Android,Mac。
default_platform :ios
platform :ios do
#這個指的是在執(zhí)行每一個lane之前都先執(zhí)行這個功能。
before_all do
cocoapods
end
#一個lane的描述,一般說明lane的用途。
desc "Runs all the tests"
lane :test do
scan
end
desc "Submit a new Beta Build to 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: "kdzs") # Build your app - more options available
pilot
# sh "your_script.sh"
# You can also use other beta testing services here (run `fastlane actions`)
end
desc "Deploy a new version to the App Store"
lane :release do
# match(type: "appstore")
# snapshot
gym(scheme: "kdzs") # Build your app - more options available
deliver(force: true)
# frameit
end
# You can define as many lanes as you want
#在每個lane執(zhí)行之后都執(zhí)行這個功能。
after_all do |lane|
# This block is called, only if the executed lane was successful
# slack(
# message: "Successfully deployed new App Update."
# )
end
#在每個lane執(zhí)行出錯的時候都執(zhí)行這個功能。
error do |lane, exception|
# slack(
# message: exception.message,
# success: false
# )
end
end
上傳 ipa 到蒲公英或者Fir.im上
上傳到蒲公英上
上傳 ipa 的命令如下:
$ ipa distribute:pgyer -f path/to/ipa -u USER_KEY -a APP_KEY
其中USER_KEY 和APP_KEY 可以在蒲公英上查到。
上傳到Fir.im上
利用 fir-cli 將打好的包,通過命令,上傳到Fir.im平臺上
FIR.im CLI 使用 ruby 構(gòu)建,只要安裝相應(yīng) ruby gem 即可:
$ gem install fir-cli —verbose
上傳 ipa 的命令如下:
$ fir publish path/to/ipa -T YOUR_FIR_TOKEN
其中 YOUR_FIR_TOKEN 可以在 Fir.im 上查到。
完整 Fastfile 代碼
fastlane_version "2.28.7"
default_platform :ios
def archive(path, name, scheme, method)
gym(
export_method: method,
scheme: scheme,
clean: true,
output_directory: path,
output_name: name,
configuration: 'Release',
include_symbols: false,
include_bitcode: true,
)
end
platform :ios do
desc "打包 type 1: 正式, 0: 測試"
lane :archive do |options|
time = Time.new.strftime("%Y-%m-%d-%H:%M:%S")
path = "./fastlane/" + time
type = options[:type]
# 使用證書創(chuàng)建私鑰及簽名
cert
# 不帶adhoc參數(shù),sigh會自動生成App Store證書(公司或個人帳戶)
sigh(
adhoc: true,
force: true,
)
if type == '1'
name = '正式'
archive(path, name, 'yourTargetName', 'app-store')
elsif type == '0'
name = '測試'
archive(path, name, 'yourTargetName', 'ad-hoc')
# 上傳至蒲公英
system 'ipa distribute:pgyer -f ./' + time + '/' + name + '.ipa -u your_user_key -a your_app_key'
# 上傳至fir
system 'fir publish ./' + time + '/' + name + '.ipa -T your_token'
else
puts "type錯誤, type == '0' : 測試, type== '1' : 正式"
end
end
end
CD 項目根目錄,就可以通過 fastlane archive type:0 來調(diào)用打包腳本了,登錄Fir.im和蒲公英平臺上我們就可以看到剛剛發(fā)布上去的APP了:


Sigh
如果你不確定證書目前是否可用,可以用Sigh自動生成獲取證書。Sigh會自動根據(jù)Appfile里設(shè)置的app_identifier從ADC(蘋果開發(fā)者中心)生成證書,并下載到項目根目錄下(不是fastlane目錄),下載后自動安裝。你可以通過指定output_path指定證書下載位置。
PS:建議不要把這個文件夾同步到項目的git中(Fastlane提供了match專門管理所有證書)??梢栽?code>.gitignore中忽略這個文件夾。
sigh 的具體用法可以參考GitHub 或者官方文檔
而且上面的兩個鏈接我都是幫你們搜好了的,直接點擊就可以到達(dá)你們想要的位置,不用謝我哈~~
Gym
Gym 是 Fastlane家族的自動化編譯工具,和其他工具配合的非常默契,它可以用來編譯,打包iOS app,生成簽名的ipa文件.下面是GitHub上的描述,我感覺更加貼切些
gym is part of fastlane: The easiest way to automate beta deployments and releases for your iOS and Android apps.
gym builds and packages iOS apps for you. It takes care of all the heavy lifting and makes it super easy to generate a signed ipa or app file ??
gym is a replacement for
shenzhen.
Deliver
我們可以使用deliver命令將屏幕截圖、元數(shù)據(jù)和 IPA 文件上傳到iTunes Connect中,
其實上傳 ITC 最主要的文件是 Deliverfile,配置好Deliverfile 后,可以刪除 metadata文件夾中的文本配置.因為Deliverfile的優(yōu)先級比metadata要高:
Values provided in the Deliverfile or Fastfile will be take priority over values from these files.
將metadata中的所有文件刪除以后,將1024*1024的icon圖標(biāo)放入到該目錄下,然后創(chuàng)建一個分級的json文件,這里假如叫做:rating.json,具體內(nèi)容如下:
{
//#0: None 無
//#1: Infrequent/Mild 偶爾/輕微的
//#2: Frequent/Intense 頻繁的/強(qiáng)烈的
//#卡通或幻想暴力
"CARTOON_FANTASY_VIOLENCE": 0,
//#現(xiàn)實暴力
"REALISTIC_VIOLENCE": 0,
//#大量露骨或殘暴的現(xiàn)實暴力
"PROLONGED_GRAPHIC_SADISTIC_REALISTIC_VIOLENCE": 0,
//#低俗笑話
"PROFANITY_CRUDE_HUMOR": 0,
//#成人/性暗示題材
"MATURE_SUGGESTIVE": 0,
//#恐怖/驚悚題材
"HORROR": 0,
//#醫(yī)學(xué)/醫(yī)療信息
"MEDICAL_TREATMENT_INFO": 0,
//#使用或提及煙、酒或毒品
"ALCOHOL_TOBACCO_DRUGS": 0,
//#模擬賭博
"GAMBLING": 0,
//#色情或裸露內(nèi)容
"SEXUAL_CONTENT_NUDITY": 0,
//#色情及裸體畫面
"GRAPHIC_SEXUAL_CONTENT_NUDITY": 0,
//#無限制的網(wǎng)站訪問
"UNRESTRICTED_WEB_ACCESS": 0,
//#賭博和競賽
"GAMBLING_CONTESTS": 0
}
具體配置參加官方文檔

Deliverfile的具體配置可以參考:Deliverfile文檔
發(fā)布到App Store
先看下lane
desc "發(fā)布到AppStore"
# 任務(wù)名稱
lane :Release do
# 創(chuàng)建 ITC 中的 App 信息
produce(
#通常這兩項是通過AppFile加載,因此這里不需要手動指定;
#username: "admin@sutongwang.cn",
#app_identifier: "gzp.fastlane.test",
app_name: "fastlane測試",
language: "zh-Hans",
app_version: "1.0",
sku: "gzp.fstlane.test"
)
# 使用證書創(chuàng)建私鑰及簽名
cert
# 每次運行時創(chuàng)建新的配置文件
sigh(force: true)
# 指定輸出目錄
gym(
output_directory: './build',
configuration: 'Release',
include_symbols: false,
include_bitcode: true,
)
# 上傳所有信息到App Store
deliver(
force: true,
#自動發(fā)布,false:手動發(fā)布
#submit_for_review: true
)
end
配置完之后執(zhí)行: fastlane Release
發(fā)布成功以后fastlane會給我一個?? 祝賀一下,哈哈 ,同時會告訴我們幫我們節(jié)省了多長時間,如下圖:

發(fā)布到CocoaPods公開庫或者是私有庫
desc "編譯\上傳CocoaPods庫"
lane :PushPodsLib do |options|
targetName = options[:targetName] #項目名稱
commitMsg = options[:commitMsg] #commit 日志信息
tagName = options[:tagName] #標(biāo)簽名稱
path = "#{targetName}.podspec"
# 根據(jù)我們制定的自動化流程去寫對應(yīng)的action
# pod install
cocoapods(
podfile: "./Example/Podfile"
)
# git add .
git_add(path: ".")
# git commit -m "xxx"
git_commit(path: ".", message: commitMsg)
# git push origin master
push_to_git_remote
# 判斷標(biāo)簽是否已經(jīng)存在
# 如果存在, 應(yīng)該刪除標(biāo)簽(本地標(biāo)簽, 遠(yuǎn)程標(biāo)簽)
if git_tag_exists(tag: tagName)
UI.message("已經(jīng)發(fā)現(xiàn)存在#{tagName}這個標(biāo)簽, 此處, 刪除該標(biāo)簽對應(yīng)的本地和遠(yuǎn)程標(biāo)簽")
remove_tag(tagName: tagName)
end
# git tag -a '#{tag}'
add_git_tag(
tag: tagName
)
# git push --tags
push_git_tags
# pod lib lint
pod_lib_lint(allow_warnings: true)
#通過trunk push到Cocoapods公開庫中
# pod trunk push "#{targetName}.podspec"
pod_push(path: path,allow_warnings:true)
## You may also push to a private repo instead of Trunk 發(fā)布到私有庫中
# pod repo push XMGFMSpecs "#{targetName}.podspec"
# pod_push(path: "#{targetName}.podspec", repo: repoName, allow_warnings:true)
其中git_tag_exists在fastlane的Action中并不存在的,所以需要我們自定義一個這樣判斷tag是否存在的Action,如果tag存在,則刪除本地和遠(yuǎn)程的tag,具體是如何自定義的,可以參考我的GitHub
其實長得都差不多,這里我就不再截圖了.....
寫在最后
我只想說碼字真的很傷腦,尤其是想把一個東西講明白就更燒腦
參考:
GitHub