1. 程式人生 > >Fastlane帶來的全自動化部署

Fastlane帶來的全自動化部署

參與 通過 lang als 集成 文件夾 工作 查看 裏的

From: Hailong‘s Blog (格式比專欄的好!)

作為公司的iOS程序員,少不了在發布應用的時候各種等待。標準的手動發布流程是:編譯->打包上傳->填寫應用更新數據->等待iTunesConnect編譯->選擇版本發布,整個過程大概需要30分鐘左右。關鍵是這個過程就像windows裝系統一樣,雖然手工參與的不多,但是要一直守在電腦前等著。

程序員這麽懶,一定會想辦法讓他自動化的。後來發現特別懶的Felix Krause · GitHub)寫的Fastlane,Fastlane可以非常快速簡單的搭建一個自動化發布服務,並且支持Android,iOS,MacOS。他可以實現一條命令從編譯

選版發布全程不用幹預。作為程序員的你只要一條命令,看集美劇,發布就完成了。截止剛剛Fastlane官網上宣稱已經為程序員節省了4百萬小時+

這是一篇中速入門,看完這篇文章,自己搭建個「iOS自動發布服務」肯定是沒問題了。這篇文章很長,有很多細節,可以當文檔查。

文章難度:★☆☆☆☆

系統要求

  • 會編程
  • Xcode7+
  • Mac OS 10.11+

Fastlane組件

Fastlane是一套工具集,包括:

  • 測試
    • scan => 自動運行測試工具,並且可以生成漂亮的HTML報告
  • 證書,配置文件
    • cert => 自動創建管理iOS代碼簽名證書
    • sigh => 一聲嘆息啊,這麽多年和Provisioning Profile戰鬥過無數次。總是有這樣那樣的問題導致配置文件過期或者失效。sigh是用來創建、更新、下載、修復Provisioning Profile的工具。
    • pem => 自動生成、更新推送配置文件
    • match => 一個新的證書和配置文件管理工具。我會另寫一篇文章專門介紹這個工具。他會所有需要用到的證書傳到git私有庫上,任何需要配置的機器直接用match同步回來就不用管證書問題了,小團隊福音啊!
  • 截圖
    • snapshot => 用Xcode7推出的UI test功能實現自動化截圖
    • frameit => 可以把截的圖片自動套上一層外邊框
  • 編譯
    • shenzhen => 當年大名鼎鼎的自動編譯工具,現在已經被棄用
    • gym => Fastlane家族的自動化編譯工具,和其他工具配合的非常默契
  • 發布
    • produce => 如果你的產品還沒在iTunes Connect(iTC)或者Apple Developer Center(ADC)建立,produce可以自動幫你完成這些工作
    • deliver => 自動上傳截圖,APP的元數據,二進制(ipa)文件到iTunes Connect
  • TestFlight管理
    • pilot => 管理TestFlight的測試用戶,上傳二進制文件
    • boarding => 建立一個添加測試用戶界面,發給測試者,可自行添加郵件地址,並同步到iTC
  • 輔助工具
    • spaceship => 為pilot,boarding和deliver等工具提供和 iTC 和 ADC 的交互API。spaceship本來是個獨立的項目,後來被Fastlane收編進來
    • WatchBuild => 是一個獨立的iTC監控工具,開啟WatchBuild可以監控iTC上的文件狀態,彈出MacOS自帶的Notification
  • 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非常像

一個簡單的發布流程:

lane :deploy do
  # 執行 pod instasll
  cocoapods
  # 執行 carthage bootstrap
  carthage
  # 增加build版本號
  increment_build_number
  # 編譯代碼
  gym
  # 發布到Apple Store
  deliver(force: true)
end

安裝

蘋果的系統升級率非常高,所以現在絕大部分開發者電腦應該是滿足依賴要求的。

確保Xcode Command Line Tools 安裝了最新版

xcode-select --install

如果你單獨安裝過ruby(如果你能看得懂這句),去掉sudo。如果使用系統自帶的ruby,需要sudo權限

[sudo] gem install fastlane
  • 如果在安裝中速度過慢,請參照更改Gem鏡像。

初始化

在項目根目錄下,初始化Fastlane:

fastlane init

提問了你的Apple ID,Team的問題之後,fastlane會自動檢測當前目錄下項目的App Name和App Identifier。如果檢測的不對,選擇n自行輸入。

接下來會問你這個app是否需要在iTC和ADC中創建(上一步中如果選擇y會自動檢測是否需要創建),fastlane會調用produce進行初始化,如果現在還不想創建,也可以之後再運行produce init進行這個流程。如果不執行produce的流程,deliver的流程也會被掠過,當然之後也可以deliver init運行完全一樣的流程。

在執行deliver init的過程中,會同步iTC中的所有語言的元數據和截圖,並按照目錄結構組織好。目錄結構應該類似下面:

fastlane
├── Appfile
├── Deliverfile
├── Fastfile
├── metadata
│   ├── copyright.txt
│   ├── en-US
│   │   ├── description.txt
│   │   ├── keywords.txt
│   │   ├── marketing_url.txt
│   │   ├── name.txt
│   │   ├── privacy_url.txt
│   │   ├── release_notes.txt
│   │   └── support_url.txt
│   ├── primary_category.txt
│   ├── primary_first_sub_category.txt
│   ├── primary_second_sub_category.txt
│   ├── secondary_category.txt
│   ├── secondary_first_sub_category.txt
│   ├── secondary_second_sub_category.txt
│   └── zh-Hans
│       ├── description.txt
│       ├── keywords.txt
│       ├── marketing_url.txt
│       ├── name.txt
│       ├── privacy_url.txt
│       ├── release_notes.txt
│       └── support_url.txt
└── screenshots
    ├── README.txt
    ├── en-US
    │   ├── 一堆png圖片

這裏肯定會被創建的是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:

  1. 這裏有個小問題,iTC和ADC中的Team ID是不一樣的,在fastlane init中只會自動在Appfile裏寫入ADC的team_id,所以在這個過程中會不停的問你iTC的Team ID,所以在創建完Appfile後,手動在裏面添加itc_team_id。
  2. 這個問答對不同的項目可能有各種各樣的分支。我已經用不同的項目試過很多次了,但是可能還不是全部,所以你還需要見招拆招。
  3. 在這裏可以安心的輸入密碼,所有的密碼都加密保存在系統的Keychain裏。

插件

Fastlane的插件是一個或者一組action的打包,單獨發布在fastlane之外。Fastlane Plugin 指南

自從16年5月份推出插件系統以來,現在已經有很多第三方的插件可以使用。查看所有插件:

fastlane search_plugins

這裏介紹兩個下文會用到的插件:

  1. fastlane-plugin-versioning => 用來修改build版本號和version版本號。

    Fastlane內嵌的actionincrement_build_number使用的是蘋果提供的agvtool,agvtool在更改Build的時候會改變所有target的版本號。這時如果你在一個工程裏有多個產品的話,每次編譯,所有的Build都要加1,最後就不知道高到哪裏去了。

    有了fastlane-plugin-versioning不僅可以指定target增加Build,而且可以按照「語義化版本」規範增加Version,當然也可以直接設定Version。

    PS:最開始寫iOS時不知道怎麽定義Build。現在我一般都直接定義成純數字,比如100起,每次編譯的時候讓他自動加一。

  2. fastlane-plugin-firim => 直接把AdHoc或者InHouse打包的ipa上傳到fir.im,供測試下載。

安裝上面的插件

fastlane add_plugin [name] # 安裝方法
fastlane add_plugin versioning
fastlane add_plugin firim

配置發布流程

可以把二進制發布到三個地方:

  • 發布測試版到Fir.im
  • 發布測試版到TestFlight (這個留到下篇文章寫)
  • 發布到Apple Store

發布到

Lane

有了Fastfile,就可以添加自己的發布流程了。打開Fastfile文件(這裏我用Sublime 設定語法為Ruby),如果不出意外的話你生成的Fastfile和我應該差不多。這裏我就不貼出來了。

最開始定義了

  • fastlane_version => 指定fastlane最小版本
  • default_platform => 指定當前平臺,可選ios,android,mac

在platform中就是需要修改的重點。先忽略before_all,after_all,error這些方法,這裏的lane就是一組任務,上傳到Firim的任務如下

lane :to_firim do
  # 如果你用 pod install
  cocoapods
  # 如果你沒有申請adhoc證書,sigh會自動幫你申請,並且添加到Xcode裏
  sigh(adhoc: true)
  # 以下兩個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: ‘./firim‘,
    export_options: {
      method: "ad-hoc", # 這可以不指定
      thinning: "<none>"
    }
    )
  # 上傳ipa到fir.im服務器,在fir.im獲取firim_api_token
  firim(firim_api_token: [firim_api_token])
end

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。 初始化:

gym init

Firim

是一個ipa托管網站。你可以用AdHoc或者In-House的方式打包,上傳到發送給測試人員測試。需要先註冊Fir.im帳戶,並生成Token。這種方式適合:

  • 小團隊 => 測試的機器數量很少並且非常可控。直接連上開發機,真機調試一次,就可以添加
  • 土豪 => 有企業帳戶可以打In-House的包

Firim常用配置項:

Name Type Description Default firim_api_token string 指定的token ipa string ipa地址 如果使用gym,可以通過上下文獲取 icon string icon的path,註意這裏有個非常坑的地方,只支持jpg格式的圖片

還有項如app_name等等,是用來配置頁面屬性的。firim --help

Firim的配置文件是Firimfile。初始化:

firim init

Firim是我完全仿照fastlane組件的方式寫的,所以也可以單獨作為CLI使用。

如果有任何Firim的問題請到Firim的issues提問。

發布

配置完以上項,就可以一條命令發布到了:

fastlane to_firim

發布到App Store

Lane

先看下lane:

lane :deploy do
  # 如果你用 pod install
  cocoapods
  # 不帶adhoc參數,sigh會自動生成App Store證書(公司或個人帳戶)
  sigh
  increment_build_number_in_plist(target: [target_name])
  increment_version_number_in_plist(
    target: [target_name],
    version_number: ‘7.1.3‘
    )
  # 指定輸出目錄
  gym(
    output_directory: ‘./build‘,
    )
  # 上傳所有信息到App Store
  deliver(force: true)
end

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中投放了廣告。

      技術分享
      submission_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

發布

配置後,還是一條命令:

fastlane deploy

Fastlane帶來的全自動化部署