くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

FlutterにFirebaseを導入してみる(FlutterFire CLI+Flavor)

ひさびさにFlutterのセットアップをしてたら、
FlutterFire CLIを使った形になってて、かなりハマったので、
いろいろ調べたときの備忘録(*´ω`*)

CLIのインストール/セットアップ

まずはCLIとかのセットアップ。

# firebase CLIのインストール
$ brew install firebase-cli

# firebase CLIのログイン
$ firebase login

# FlutterFire CLIのインストール
$ fvm dart pub global activate flutterfire_cli

# HOMEに配置されるのでPATHを通す
$ export PATH="$PATH":"$HOME/.pub-cache/bin"

# FlutterFireの設定
$ flutterfire configure \
  --platforms="android,ios,macos,web"
  -p <projectId> \
  -i <ios-bundle-id> \
  -a <android-package-name> \
  -m <macos-bundle-id> \
  -o lib/firebase_options.dart
  --pratforms="android,ios,macos,web"

FlutterFire CLI

いつのまにか便利ツールが増えていた。

flutterfire configureでは、以下のことをしてくれる

  • Firebaseプロジェクトへのアプリの登録
  • FirebaseConfigの取得/生成
    • lib/firebase_options.dart
    • ios/Runner/GoogleService-Info.plist
    • ios/firebase_app_id_file.json
    • macos/Runner/GoogleService-Info.plist
    • macos/firebase_app_id_file.json
    • android/app/google-services.json
  • 設定ファイルの編集
    • android/build.gradle

をしてくれる。
ためしてないけど、プロジェクトも作成できるっぽい。

GoogleService-Info.plistfirebase_app_id_file.json
google-services.jsonなどは、使うモジュールによって要否が変わるよう。

authanalyticscrashlyticsあたりで必要なため、
必須だと思っておくほうがいいかも。

また、flutter_flavorizrなどでfirebase関連の設定を追加していると、ハマったりする。。

flutter_flavorizrを使うと、XCodeのBuild Phasesに
Firebase SetupというRun Scriptが追加されるが、
この中でGoogleService-Info.plistをコピーなどをしているので、
処理を外しておいたりしないと、エラーになったりする。。
(かなりハマった。。)

パッケージのインストール

あとは必要なパッケージをインストールして、
各種設定をしていく感じ。

# コアパッケージのインストール
$ fvm flutter pub add firebase_core

# 必要なパッケージのインストール
$ fvm flutter pub add firebase_auth
$ fvm flutter pub add firebase_analytics
$ fvm flutter pub add firebase_messaging
$ fvm flutter pub add firebase_crashlytics
$ fvm flutter pub add cloud_firestore
$ fvm flutter pub add firebase_storage
$ fvm flutter pub add cloud_functions
$ fvm flutter pub add firebase_performance
$ fvm flutter pub add firebase_in_app_messaging
$ fvm flutter pub add firebase_database
$ fvm flutter pub add firebase_remote_config
$ fvm flutter pub add firebase_dynamic_links

dartでのFirebaseの初期化

あとは、runApp()の前にFirebaseの初期化処理を追加する。

生成したlib/firebase_options.dartに構成情報が含まれるので、
それを使ってFirebase.initializeApp()で初期化する

import 'dart:async';

import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import 'package:firebase_core/firebase_core.dart';

import '/firebase_options.dart';
import 'app.dart';

FutureOr<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Firebaseの初期化
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  // runApp
  runApp(const ProviderScope(child: App()));
}

あとは、必要なパッケージを追加してあげればOK

FlutterFire CLIでのFlavor対応

このIssueで議論されている通り、
FlutterFireCLIはflavorには対応していないため、
自前で設定が必要になる。

また、すでにplistjsonが存在すると、エラーになるため、
隠しオプション(--no-apply-gradle-plugins--no-app-id-json)が用意されていて、
生成をしないようにしてエラーにならないようにはできるけど、
ファイルの準備を手動でしないといけないので、すこしめんどくさい。。

なお、公式のflavor対応方法はこれ。

--dart-define-from-fileを使った方法もあるらしい。

flavorごとに設定ファイルを用意

出力ファイルはflavorごとに行うけど、
適切な場所に退避するようにしておく。

#!/bin/bash
# setup_firebase.sh

set -e

ANDROID_PKG_NAME="..."
IOS_BUNDLE_ID="..."
PROJECT_ID_PROD="..."
PROJECT_ID_DEV="..."

FLAVORS='
dev
stag
prod
'

for f in $FLAVORS; do
  # flavorによって切り替える
  if [ "$f" = "prod" ]; then
    PROJECT_ID="$PROJECT_ID_PROD"
    SUFFIX=""
  else
    PROJECT_ID="$PROJECT_ID_DEV"
    SUFFIX=".${f}"
  fi
  
  # 各種ファイルの設定
  flutterfire configure --yes \
  --platforms="android,ios,macos,web" \
  --project="${PROJECT_ID}" \
  --android-package-name="${ANDROID_PKG_NAME}${SUFFIX}" \
  --ios-bundle-id="${IOS_BUNDLE_ID}${SUFFIX}" \
  --macos-bundle-id="${IOS_BUNDLE_ID}${SUFFIX}" \
  --out="lib/firebase_options_${f}.dart"

  # 生成したファイルの移動
  mv -v android/app/google-services.json android/app/src/${f}/ 
  mv -v ios/Runner/GoogleService-Info.plist ios/Runner/${f}/
  mv -v ios/firebase_app_id_file.json ios/Runner/${f}/ 
  mv -v macos/Runner/GoogleService-Info.plist macos/Runner/${f}/
  mv -v macos/firebase_app_id_file.json macos/Runner/${f}/ 
done

各種ファイルはこんな感じに配置しておく。

lib/
  firebase_options_dev.dart
  firebase_options_stag.dart
  firebase_options_prod.dart
android/
  app/src/dev/
    google-services.json
  app/src/stag/
    google-services.json
  app/src/prod/
    google-services.json
ios/ # macos/も同じ
  Flutter/
    devDebug.xcconfig
    ...
  Runner/dev/
    GoogleService-Info.plist
    firebase_app_id_file.json
  Runner/stag/
    GoogleService-Info.plist
    firebase_app_id_file.json
  Runner/prod/
    GoogleService-Info.plist
    firebase_app_id_file.json

Androidの設定

build.gradleの設定、flutter_flavorizrのを流用

// app/build.gradle
android {
  // ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) -----
  flavorDimensions "flavor-type"
  productFlavors {
    dev {
      dimension "flavor-type"
      applicationId "..."
      resValue "string", "app_name", "DEV: ..."
    }
    stag {
      dimension "flavor-type"
      applicationId "..."
      resValue "string", "app_name", "STAG: ..."
    }
    prod {
      dimension "flavor-type"
      applicationId "..."
      resValue "string", "app_name", "..."
    }
  }
  // ----- END flavorDimensions (autogenerated by flutter_flavorizr) -----
}

productFlavorsを使えば、設定ファイルの切り替えは、
Android側でよしなにやってくれるのでこれだけでOK

iOS/Macの設定

iOS/Mac側もflutter_flavorizrのを流用。

変更点としては、
flutter_flavorizrがXCodeのBuild Phasesに追加した
Firebase SetupというRun Scriptの中身。

場所としては、xed iosXCodeを開いて、
「左パネルのRuntter > TARGETSのRunner > Build Phasesタブ」にある、
Firebase Setupを開く。

変更前のスクリプト(flutter_flavorizrが生成)

if [ "$CONFIGURATION" == "Debug-dev" ] || [ "$CONFIGURATION" == "Release-dev" ]; then
  cp Runner/dev/GoogleService-Info.plist Runner/GoogleService-Info.plist
elif [ "$CONFIGURATION" == "Debug-stag" ] || [ "$CONFIGURATION" == "Release-stag" ]; then
  cp Runner/stag/GoogleService-Info.plist Runner/GoogleService-Info.plist
elif [ "$CONFIGURATION" == "Debug-prod" ] || [ "$CONFIGURATION" == "Release-prod" ]; then
  cp Runner/prod/GoogleService-Info.plist Runner/GoogleService-Info.plist
fi

変更後のスクリプト

cp "Runner/$ASSET_PREFIX/GoogleService-Info.plist" Runner/GoogleService-Info.plist
cp "Runner/$ASSET_PREFIX/firebase_app_id_file.json" Runner/firebase_app_id_file.json

ios/Flutter/devDebug.xcconfigにある
ASSET_PREFIXを使ってシンプルにしている。

#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"
#include "Generated.xcconfig"

FLUTTER_TARGET=lib/main_dev.dart
ASSET_PREFIX=dev
BUNDLE_NAME=DEV: ...
BUNDLE_DISPLAY_NAME=DEV: ...

ビルド時に所定の場所に配置する形。

Firebase Setupを手動で追加するときには、順序に気をつける。
[CP] Check Pods Manifest.lockの後だとうまくいくっぽい?


以上!! これでとりあえず、FlutterにFirebaseを導入できるようになった。。(*´ω`*)

参考にしたサイトさま