遵循 Flutter 的持續交付(Continuous Delivery, CD)最佳實踐,確保你的應用程式能夠頻繁地交付給 Beta 測試者並進行驗證,而無需依賴手動工作流程。

CI/CD 選項

#

有多種持續整合(Continuous Integration, CI)與持續交付(Continuous Delivery, CD)工具可用,以協助自動化你的應用程式交付流程。

內建 Flutter 功能的全方位解決方案

#

將 fastlane 整合至現有工作流程

#

你可以將 fastlane 與以下工具結合使用:

本指南將說明如何設定 fastlane,並將其整合到你現有的測試與持續整合(CI)工作流程中。更多資訊請參閱「Integrating fastlane with existing workflow」。

fastlane

#

fastlane 是一套開源工具組,用於自動化應用程式的發佈與部署。

本地端設定

#

建議你在遷移到雲端系統之前,先於本地端測試建置與部署流程。你也可以選擇直接在本地機器上執行持續交付。

  1. 安裝 fastlane gem install fastlanebrew install fastlane。 請參閱 fastlane docs 以取得更多資訊。
  2. 建立一個名為 FLUTTER_ROOT 的環境變數, 並將其設為你的 Flutter SDK 根目錄。 (這對於部署 iOS 的腳本來說是必要的。)
  3. 建立你的 Flutter 專案,並在準備好後,確保你的專案可以透過
    • Android flutter build appbundle;以及
    • iOS flutter build ipa 進行建置。
  4. 為每個平台初始化 fastlane 專案。
    • Android 在你的 [project]/android 目錄中執行 fastlane init
    • iOS 在你的 [project]/ios 目錄中, 執行 fastlane init
  5. 編輯 Appfile,以確保其中包含你應用程式所需的完整中繼資料。
    • Android 檢查 package_name[project]/android/fastlane/Appfile 中是否與 AndroidManifest.xml 的套件名稱相符。
    • iOS 檢查 app_identifier[project]/ios/fastlane/Appfile 中是否也與 Info.plist 的 bundle identifier 相符。請填入 apple_iditc_team_idteam_id 為你的帳戶資訊。
  6. 設定本地端的商店登入憑證。
    • Android 請依照 Supply 設定步驟 操作,並確保 fastlane supply init 能成功從你的 Play Store 控制台同步資料。 請將 .json 檔案視同密碼,不要將其提交到任何公開的原始碼控制庫。
    • iOS 你的 iTunes Connect 使用者名稱已經 在 Appfileapple_id 欄位中。請將 FASTLANE_PASSWORD shell 環境變數設為你的 iTunes Connect 密碼。否則,在上傳到 iTunes/TestFlight 時會被要求輸入。
  7. 設定程式碼簽章。
    • Android 請參考 Android app signing steps
    • iOS 在 iOS 上,當你準備好使用 TestFlight 或 App Store 進行測試與部署時,請建立並使用發佈(distribution)憑證來簽署,而非開發(development)憑證。
      • 請在你的 Apple Developer Account console 建立並下載發佈憑證。
      • open [project]/ios/Runner.xcworkspace/ 並在目標設定頁面選取發佈憑證。
  8. 為每個平台建立 Fastfile 腳本。
    • Android 在 Android 上,請參考 fastlane Android beta deployment guide。 你的修改可以很簡單,只需新增一個呼叫 upload_to_play_storelane。 將 aab 參數設為 ../build/app/outputs/bundle/release/app-release.aab, 以使用已建置好的 app bundle flutter build

    • iOS 在 iOS 上,請參考 fastlane iOS beta deployment guide。 你可以指定歸檔(archive)路徑,以避免重新建置專案。例如:

      ruby
      build_app(
        skip_build_archive: true,
        archive_path: "../build/ios/archive/Runner.xcarchive",
      )
      upload_to_testflight

你現在已經準備好可以在本地執行部署,或將部署流程遷移到持續整合(CI)系統。

在本地執行部署

#
  1. 建立 release 模式的應用程式。
    • Android flutter build appbundle
    • iOS flutter build ipa
  2. 在每個平台上執行 Fastfile 腳本。
    • Android cd android,然後 fastlane [name of the lane you created]
    • iOS cd ios,然後 fastlane [name of the lane you created]

雲端建置與部署設定

#

首先,請依照「Local setup」章節所述,先完成本地端的設定,確保流程可行,再遷移到如 Travis 這類雲端系統。

主要需要注意的是,因為雲端執行個體是短暫且不受信任的,你不應將 Play Store 服務帳戶的 JSON 憑證或 iTunes 發行憑證等憑證留在伺服器上。

持續整合(CI)系統通常支援加密環境變數來儲存私密資料。你可以在建置應用程式時,透過 --dart-define MY_VAR=MY_VALUE 傳遞這些環境變數。

請特別注意,不要在測試腳本中將這些變數值重新輸出到主控台。 這些變數在 pull request 尚未合併前也不會提供,以確保惡意人士無法建立會輸出這些機密的 pull request。請小心處理你接受並合併的 pull request 中與這些 secrets 的互動。

  1. 讓登入憑證成為短暫性(ephemeral)。

    • Android 在 Android 上:
      • Appfile 移除 json_key_file 欄位,並將 JSON 的字串內容存放於 CI 系統的加密變數中。 在你的 Fastfile 中直接讀取該環境變數。
        upload_to_play_store(
          ...
          json_key_data: ENV['<variable name>']
        )
      • 將你的上傳金鑰進行序列化(例如,使用 base64),並將其儲存為加密的環境變數。你可以在 CI 系統的安裝階段進行反序列化,方法如下:
        bash
        echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > [path to your upload keystore]
    • iOS 在 iOS 上:
      • 將本機環境變數 FASTLANE_PASSWORD 移至 CI 系統上,改用加密環境變數。
      • CI 系統需要存取你的發佈憑證。建議使用 fastlane 的 Match 系統來同步多台機器間的憑證。
  2. 建議使用 Gemfile,而非每次在 CI 系統上執行不確定性的 gem install fastlane,以確保 fastlane 相依套件在本地與雲端機器間的穩定性與可重現性。不過,此步驟為選用。

    • 在你的 [project]/android[project]/ios 資料夾中,建立一個 Gemfile,內容如下:
      source "https://rubygems.org"
      
      gem "fastlane"
    • 在兩個目錄中都執行 bundle update,並將 GemfileGemfile.lock 一併提交到原始碼控制系統。
    • 本機執行時,請使用 bundle exec fastlane 取代 fastlane
  3. 在你的儲存庫根目錄建立 CI 測試腳本,例如 .travis.yml.cirrus.yml

    • 請參閱 fastlane CI 文件 以進行 CI 特定的設定。
    • 將你的腳本分片,以便能在 Linux 與 macOS 平台上執行。
    • 在 CI 任務的設定階段,請執行下列動作:
      • 使用 gem install bundler 確認 Bundler 已可用。
      • [project]/android[project]/ios 中執行 bundle install
      • 確認 Flutter SDK 已可用,並已設定於 PATH
      • Android 平台請確保 Android SDK 可用,且已設定 ANDROID_SDK_ROOT 路徑。
      • iOS 平台可能需要指定對 Xcode 的相依性 (例如 osx_image: xcode9.2)。
    • 在 CI 任務的腳本階段:
      • 根據平台執行 flutter build appbundleflutter build ios --release --no-codesign --config-only
      • cd androidcd ios
      • bundle exec fastlane [name of the lane]

Xcode Cloud

#

Xcode Cloud 是一項持續整合與交付(CI/CD)服務,用於建置、 測試與發佈 Apple 平台上的應用程式與框架。

系統需求

#

自訂建置腳本

#

Xcode Cloud 支援 自訂建置腳本,可用於在指定時機執行額外任務。它同時包含一組 預設環境變數,例如 $CI_WORKSPACE,這是你被複製下來的儲存庫位置。

Post-clone 腳本

#

利用 post-clone 自訂建置腳本,讓其在 Xcode Cloud 複製你的 Git 儲存庫後執行,請依照下列指示操作:

ios/ci_scripts/ci_post_clone.sh 建立一個檔案,並加入以下內容。

sh
#!/bin/sh

# Fail this script if any subcommand fails.
set -e

# The default execution directory of this script is the ci_scripts directory.
cd $CI_PRIMARY_REPOSITORY_PATH # change working directory to the root of your cloned repo.

# Install Flutter using git.
git clone https://github.com/flutter/flutter.git --depth 1 -b stable $HOME/flutter
export PATH="$PATH:$HOME/flutter/bin"

# Install Flutter artifacts for iOS (--ios), or macOS (--macos) platforms.
flutter precache --ios

# Install Flutter dependencies.
flutter pub get

# Install CocoaPods using Homebrew.
HOMEBREW_NO_AUTO_UPDATE=1 # disable homebrew's automatic updates.
brew install cocoapods

# Install CocoaPods dependencies.
cd ios && pod install # run `pod install` in the `ios` directory.

exit 0

此檔案應加入至你的 git 儲存庫,並標記為可執行檔。

git add --chmod=+x ios/ci_scripts/ci_post_clone.sh

工作流程設定

#

一個 Xcode Cloud 工作流程 定義了當你的工作流程被觸發時,在 CI/CD 流程中所執行的步驟。

要在 Xcode 中建立新的工作流程,請依照以下指示操作:

  1. 選擇 Product > Xcode Cloud > Create Workflow,以開啟 Create Workflow 視窗。

  2. 選擇此工作流程應附加的產品(App),然後點擊 Next 按鈕。

  3. 下一個視窗會顯示 Xcode 提供的預設工作流程總覽, 你可以點擊 Edit Workflow 按鈕進行自訂。

分支變更

#

預設情況下,Xcode 會建議使用 Branch Changes 條件,當你的 Git 儲存庫的預設分支有任何變更時,會啟動新的建置。

對於你的 App 的 iOS 版本,通常你會希望在修改 Flutter 套件,或是在 lib\ios\ 目錄下變更 Dart 或 iOS 原始碼檔案後,讓 Xcode Cloud 觸發你的工作流程。

你可以透過以下的 Files and Folders 條件來達成:

Xcode Workflow Branch Changes

下一個建置號碼

#

Xcode Cloud 會將新工作流程的建置號碼預設為 1,並在每次成功建置後自動遞增。如果你使用的是已有較高建置號碼的現有 App,你需要在工作流程中指定 Next Build Number,以讓 Xcode Cloud 使用正確的建置號碼。

請參考 設定 Xcode Cloud 建置的下一個建置號碼 以取得更多資訊。