Flutter 裡的持續部署

透過 Flutter 持續交付的最佳實踐,確保你的應用程式交付給你的 Beta 版本測試人員並能夠頻繁予以驗證,而無需藉助手動工作流程。

CI/CD 選擇

有許多持續整合 (CI) 和持續交付 (CD) 的工具,幫助自動發布你的應用。

內建 Flutter 的多合一 (All-in-one) 選擇:

使用 Fastlane 與現有工作流程整合

你可以透過下面的工具使用 fastlane:

這份指南展示了如何讓設定 fastlane 以及將其整合到現有應用的測試和持續整合 (CI) 工作流當中去。更多相關的內容,請參考上面這部分的內容。

fastlane

fastlane 是一個開源工具套件,幫助你自動的打包正式版以及部署你的應用。

本地設定

建議在遷移到基於雲端運算的系統之前,先在本地測試其建立和部署流程。你還可以使用本地機器執行連續交付。

  1. 安裝 fastlane gem install fastlanebrew install fastlane。訪問 fastlane docs 以獲得更多訊息。

  2. 建立一個名為 FLUTTER_ROOT 的環境變數,並將其設定為 Flutter SDK 的根目錄。(這是為 iOS 部署的指令碼所必需的。)

  3. 建立你的 Flutter 專案,準備就緒後,確保透過如下途徑建立專案:

    • Android flutter build appbundle; and
    • iOS flutter build ipa.
  4. 初始化各平台的 fastlane 專案:

    • Android:在 [project]/android 目錄中,執行 fastlane init 指令。

    • iOS:在 [project]/ios 目錄下,執行 fastlane init 指令。

  5. 編輯 Appfile 以確保它有應用程式的基本資料設定:

    • Android 檢查在 [project]/android/fastlane/Appfile 檔案中的 package_name 是否對應在 AndroidManifest.xml 中的套件名。

    • iOS 檢查在 [project]/ios/fastlane/Appfile 中的 app_identifier 是否對應 Info.plist 檔案中的 bundle identifier。將相應的 apple_iditc_team_idteam_id 輸入進去。

  6. 設定應用商店的本地登入憑據。

    • Android 按照 Supply setup steps 文件操作,並且確保 fastlane supply init 成功同步了你在 Google Play 商店控制台中的資料。 .json 檔案與密碼一樣重要,切勿將其公開在任何公共原始碼控制儲存庫。

    • iOS iTunes Connect 使用者名已經存在於你的 Appfileapple_id 欄位中,你需要將你的 iTunes 密碼設定到 FASTLANE_PASSWORD 這個環境變數裡。否則,上傳到 iTunes/TestFlight時會提示你。

  7. 設定程式碼簽名:

    • Android 參考文件 為應用簽名

    • iOS 在iOS上,當你準備使用 TestFlight 或 App Store 進行測試和部署時,使用分發證書而不是開發證書進行建立和簽名。

      • Apple Developer Account console 建立並下載一個分發證書。

      • 開啟 [project]/ios/Runner.xcworkspace/ 在你的專案設定裡選擇一個分發證書。

  8. 給每個不同的平台建立一個 Fastfile 指令碼。

    • Android 在 Android 上按照 fastlane Android beta deployment guide 指引操作。你可以簡單的編輯一下檔案,加一個名叫 upload_to_play_storelane。為了使用 flutter build 指令編譯 aab,要把 apk 引數設定為 ../build/app/outputs/bundle/release/app-release.aab

    • iOS 在 iOS 上,按照 fastlane iOS beta 部署指南 指引操作。你可以指定 archive 的路徑以避免重複建立。例如:

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

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

在本地執行部署

  1. 建立發布模式的應用:

    • Android flutter build appbundle.
    • iOS flutter build ipa.
  2. 在每個平台上執行 Fastfile 指令碼。

    • Android cd android then fastlane [name of the lane you created].
    • iOS cd ios then fastlane [name of the lane you created].

雲建立和部署設定

首先,按照『本地設定』中描述的本地設定部分,確保在遷移到 Travis 等雲系統之前,該過程有效。

需要考慮的主要事項是,由於雲實例是短暫且不可信的,因此你不能在服務器上保留你的憑據,如 Play Store 服務帳戶 JSON 或 iTunes 分發證書。

持續整合 (CI) 系統通常支援加密的環境變數來儲存私有資料。你可以使用 --dart-define MY_VAR=MY_VALUE 在建立應用時傳遞環境變數。

採取預防措施,不要在測試指令碼中將這些變數值重新回顯到控制台。 在合併之前,這些變數在拉取請求中也不可用,以確保惡意行為者無法建立列印這些金鑰的拉取請求。在接受和合並的 pull 請求中,請注意與這些金鑰。

  1. 暫時性登入憑據。

    • ![Android](https://flutter.tw/assets/images/docs/cd/android.png 在 Android 上:

      • Appfile 中刪除 json_key_file 並將其儲存在 CI 系統的加密變數裡。從 Fastfile 中直接讀取這些環境變數。

        upload_to_play_store(
          ...
          json_key_data: ENV['<variable name>']
        )
        
      • 序列化你的上傳金鑰(例如,使用 base64)並將其另存為加密環境變數。可以可以在安裝階段在 CI 系統上對其進行反序列化

        echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > [path to your upload keystore]
        
    • iOS 在 iOS 上:

      • 將本地環境變數 FASTLANE_PASSWORD 轉而使用 CI 系統的加密的環境變數。

      • CI 系統需要有許可權拿到你的分發證書。建議使用fastlane 的 Match 系統在不同的機器上同步你的證書。

  2. 建議每次使用 Gemfile 而不是 gem install fastlane 以避免其在 CI 系統上使用的不確定性,以確保 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

    • 有關特定於 CI 的設定,請參見 fastlane CI 文件

    • 分開你的指令碼以便能在 Linux 和 macOS 兩個平台執行。

    • 在 CI 的設定階段,執行下列內容:

      • 透過執行 gem install bundler 確保 Bundler 可用。

      • [project]/android[project]/ios 目錄下分別執行 bundle install指令。

      • 確保 Flutter SDK 已經正確了設定在了 PATH 環境變數中。

      • 在 Android 平台上,請確保已經設定正確的 ANDROID_SDK_ROOT 環境變數。

      • 在 iOS 平台上,你需要為 Xcode 指定依賴 (比如: osx_image: xcode9.2)

    • 在 CI 任務的指令碼階段:

      • 根據平台的不同可以執行 flutter build appbundle 或者 flutter build ios --release --no-codesign

      • 然後執行 cd androidcd ios 指令。

      • 最後執行 bundle exec fastlane [name of the lane] 指令。

Xcode Cloud

Xcode Cloud 是一項為分發 Apple 平台的持續建立整合並交付,以及測試分發的服務。

需要準備的

自定義建立指令碼

Xcode Cloud 可以識別 自定義的建立指令碼 用於在特定階段執行額外的任務。同時它還包含了一系列 預定義的環境變數,例如用於你 clone 倉庫地址的 $CI_WORKSPACE

Post-clone 指令碼

利用 post-clone 執行的自定義建立指令碼 Xcode Cloud 按照以下說明克隆你的 Git 倉庫:

ios/ci_scripts/ci_post_clone.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 workflow 定義了你工作流觸發時 CI/CD 處理程序的執行步驟。

要在 Xcode 中建立一個工作流,請參考以下步驟:

  1. 選擇 Product > Xcode Cloud > Create Workflow 以開啟 Create Workflow 選單。

  2. 選擇工作流需要作用的生產應用,然後點選 Next 按鈕。

  3. 下一步,選單將會展示一個 Xcode 提供的預設工作流的浮層,然後可以透過點選 Edit Workflow 按鈕進行定製。

變更分支

預設 Xcode 建議每次分支變更後都為你倉庫的預設分支開始一個全新的建立。

對於你應用的 iOS 變體,你通常會希望 Xcode Cloud 在對你的 Flutter packages 修改了 lib\ 中的 Dart 或 ios\ 中的 iOS 源檔案目錄之後,觸發你的工作流。

這可以透過使用下列檔案和資料夾條件來實現:

Xcode Workflow Branch Changes

下次建立的建立版本數字

Xcode Cloud 對於新的工作流來說預設的建立版本數字是 1,然後在每次成功建立後遞增。如果你已經在一個已有應用中,使用了一個更高的建立版本數字,你需要設定 Xcode Cloud 使用正確的建立版本數字,只需要簡單透過指定 Next Build Number 用於迭代即可。

你可以在 設定 Xcode Cloud 建立下一次的建立版本數字 檢視更多訊息。