yii.
← Writing
Flutter 技術 · · 6 min read

Flutter 如何根據 Flavor 多環境載入對應的 Firebase Config

這篇寫於 2023 年。工具和 API 變化很快,部分步驟可能已經不適用。

本文的內容應該很多人都會碰到,我們很常為了加速開發,會使用許多 Firebase 服務,例如:Authentication、Analytics 和 Crashlytics 等等,這時候就需要處理 Flutter 專案與 Firebase 的集成,而當我們有多個環境時如何綁定對應的 Firebase 專案?如何決定要載入哪個環境的設定檔,才能與 Firebase 服務溝通。其中比較麻煩是針對 Android、iOS(macOS相同) 有不同處理方式,但也大同小異,趕緊往下滑跟著實作吧!


Firebase Console#

本文範例設置了兩個環境,分別為 Dev、Prod,所以 Firebase Project 也區分開來,之後在設定及維護上會方便許多。當然如果你還有 staging 或是其他環境那就在創建自己的專案,我們需要從每個專案裡拿到設定檔

FlutterFire Helper#

為了不需要手動為每個平台一個一個新增到專案,我們需要 FlutterFire 工具的幫忙,它的出現就是為了讓開發者可以快速將 Flutter 專案集成 Firebase,替我們節省非常多時間

FlutterFire | FlutterFireThe official Firebase plugins for Flutterfirebase.flutter.dev

設定過程我們都需要 flutterfire_cli 指令操作,在 Terminal 透過幾個指令就能完成了,需要先進行安裝

dart pub global activate flutterfire_cli

接著在 Terminal 移動到 Flutter 專案的所在位置,使用 flutterfire configure 指令,最後產出幾個設定firebase_options 檔案

  • project 為 Firebase 專案名稱
  • out 為輸出的位置與檔案名稱
  • ios-bundle-id 為 Bundle ID
  • android-app-id 為 Package Name
  • macos-bundle-id 為 Bundle ID
  • web-app-id 為 Bundle ID

每個平台的 id 通常應該沒特別需求的話都會是相同,運行之後會詢問你要使用服務的平台,包含 ios、android、macos、web,最後產出幾個設定檔案

flutterfire config \
  --project=flaver-dev \
  --out=lib/firebase_options_dev.dart \
  --ios-bundle-id=com.flaver.food.dev \
  --android-app-id=com.flaver.food.dev \
  --macos-bundle-id=com.flaver.food.dev \
  --web-app-id=com.flaver.food.dev
  • Android 需要 google-services.json
  • iOS 與 macOS 需要GoogleService-Info.plist、firebase_app_id_file.json
  • Flutter 需要 firebase_options.dart

而在每次執行 flutterfire configure 指令後就先將檔案進行移動,避免之後在生成其他環境的檔案時造成覆蓋,要移動到哪呢?可以跳到後面的 Setup 操作。

以下為 Firebase 專案完成平台設定的情況,一下子就完成了,接下來只需要讓程式知道在每個環境下要載入對應的檔案和資料

Android Setup#

當我們設置好 Flavor 之後 android 目錄會有各環境的資料夾,我們需要將 google-services.json 放置到對應環境底下,此範例為 dev 和 prod

Android 會在 app 資料夾載入 google-services.json 檔案,所以我們需要在 Build 階段將運行環境的檔案複製到 app 這層,這樣才會正常運行哦

iOS Setup#

當我們設置好 Flavor 之後 iOS 目錄會有 GoogleService-Info.plist、firebase_app_id_file.json兩個檔案,一個會在 Runner 資料夾裡面,需要將他們放置到 flavor 資料夾,此範例為 dev 和 prod。不過這都沒有固定,你想放到哪裡都可以,最主要是好管理就好

此範例有創建 Config 資料夾,會了放置相關檔案,而因為要讓專案讀取的到,所以在 Build Phases 的 Copy Bundle Resources 需要加入資料夾

因為要讓 iOS 在 Build 階段將檔案移動到指定地點,跟 Android 一樣,需要多新增兩個任務處理。在 Build Phases 裡新增一個任務 Copy GoogleServices file(可以自行命名),在 Build 過程需要給予對應環境的 GoogleService-Info.plist,讓 APP 在每個環境運行時能載入正確的 Firebase 設定檔,才可以正常使用 Firebase 服務

environment="dev"

# Get flavor name
if [[ $CONFIGURATION =~ -([^-]*)$ ]]; then
    environment=${BASH_REMATCH[1]}
fi

GOOGLESERVICE_INFO_PLIST_NAME=GoogleService-Info.plist
GOOGLESERVICE_INFO_PLIST_FILE_PATH=${PROJECT_DIR}/Config/${environment}/${GOOGLESERVICE_INFO_PLIST_NAME}

# Check GoogleService-Info.plist file are exist or not
if [ ! -f $GOOGLESERVICE_INFO_PLIST_FILE_PATH ] 
then
    echo "No GoogleService-Info.plist found. Please ensure it's in the proper directory."
    exit 1
fi

PLIST_FILE_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist

# Copy GoogleService-Info.plist of prod for Release build
cp "${GOOGLESERVICE_INFO_PLIST_FILE_PATH}" "${PLIST_FILE_DESTINATION}"
echo "Copy ${GOOGLESERVICE_INFO_PLIST_FILE_PATH} to final destination: ${PLIST_FILE_DESTINATION}"

如果有使用到 Firebase Crashlytic 服務,Build Phases 會有 [firebase_crashlytics] Crashlytics Upload Symbols 這個任務,這時候需要針對擁有的 flavor 環境載入對應的檔案,可能會需要微調一下,將 Configuration 和路徑調整為自己專案的樣子

if [ "${CONFIGURATION}" == "Debug-dev" ] || [ "${CONFIGURATION}" == "Profile-dev" ] || [ "${CONFIGURATION}" == "Release-dev" ]; 
then
    "$PODS_ROOT/FirebaseCrashlytics/upload-symbols" --flutter-project "$PROJECT_DIR/Config/dev/firebase_app_id_file.json" 
elif [ "${CONFIGURATION}" == "Debug-prod" ] || [ "${CONFIGURATION}" == "Profile-prod" ] || [ "${CONFIGURATION}" == "Release-prod" ]; 
then
    "$PODS_ROOT/FirebaseCrashlytics/upload-symbols" --flutter-project "$PROJECT_DIR/Config/prod/firebase_app_id_file.json"
fi

如果沒有使用到 Firebase Crashlytic,就不會使用到firebase_app_id_file.json,也不需要額外設定

Flutter Setup#

在 flutterfire 生成檔案後,會在 lib 資料夾生成 firebase_options.dart,我們一樣將他們放置到其他資料夾存放,為了專案目錄架構的整潔,然後在檔名後方加上環境後綴

最後一步,在每個環境的入口,main() 使用對應的 Firebase 設定檔,讓我們在 Firebase 初始化時沒有問題,接下來就能安心開發了,很棒對吧

Firebase Service Verification#

本文使用 Firebase Crashlytics 作為範例,測試是否可以正常與 Firebase 服務互動。在 main() 使用 runZonedGuarded() 包裹,為了要捕捉未知的 Platform Error,我們在 runApp()之前就拋出測試用的例外,為了讓下方的 callback 可以被觸發,這時候就會將相關的錯誤以及 StackTrace 上傳給 Firebase Crashlytics 囉

main.dart
main.dart

當有看到 Making request to crashlyticsreports domain 的時候就代表運作正常,此時在 Crashlytics 後台可以看到原本的添加SDK文字消失,並顯示分析儀表板

到這邊看到有資料進來就代表服務運作沒問題了,也記得檢查和測試每個環境是否都正常,如果你在設定 Firebase 過程中還是有遇到問題,也很歡迎留言跟我討論~


Reference#


About#

Contribution#

如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~

https://www.buymeacoffee.com/yiichenhi

希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~

本文原刊登於 Medium。