【FlutterFire】Flutter で作成したアプリに Flutter CLI を使って Firebase を紐付けする

## ■ はじめに

### **説明**
FlutterFireってなに？という部分から、実際に Flutter で作成したアプリに  Firebase を 紐付けする部分まで解説していきます。

前提としては、

- Flutter の環境構築が出来ていること
- 適当な Project があること
- Fiarebase のアカウントがあること
- nvm（Node Version Manager）を使用するため、[Node.js](https://www.nodejs.org/) をインストールされていること（まだの方は Node.jsの部分に外部リンク貼ったので、そこから LTS版をダウンロードしてもらえればOKです）

などが挙げられます。
説明などにおいて、過不足あれば是非ご指摘下さい。

### **環境**
- Mac

```dart
% sw_vers 
ProductName:            macOS
ProductVersion:         14.0
BuildVersion:           23A344
%
```

- Dart / Flutter

```dart
% flutter --version
Flutter 3.16.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 78666c8dc5 (8 weeks ago) • 2023-12-19 16:14:14 -0800
Engine • revision 3f3e560236
Tools • Dart 3.2.3 • DevTools 2.28.4
%
```

- Firebase / flutterfire

```dart
% firebase --version
13.3.0
%
% flutterfire --version
0.2.7
%
```

### **【前提】FlutterFire について**

FlutterFire は、Flutter で作ったアプリを Firebase に接続し簡単にサービスを使用する事が出来る Firebase のプラグインです。

Firebase のサービスというと、

- Authentication（認証）
- Cloud Firestore（NoSQLのDB）
- Cloud Storage（ストレージ）

とかが有名ですが、それ以外にも画像赤線のサービスが使えるようです。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/29ba734a-8586-87bd-f92f-b920685faaa7.png)

又、Flutter & Firebase、両チームが協力して公式サポートしているようなので安全に使える点も魅力だと思いました。
ちなみに、FlutterFire CLI は Flutter 2.8 (2021/12/9) で実装された機能のようです。
それ以前は、Android / iOS毎にコードの編集やファイルダウンロード（jsonファイル・plistファイル）などが必要だったようで結構手間だったとかなんとか。（私は2024/01から Flutter の自社開発企業に入社したタイミングで本格的に Flutter を触り始めたのでその時代は知らずですが）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/02fa2a50-9d7f-835d-4bfb-9198835a0d17.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/ca99650f-7d54-e690-1091-b5bc23114d31.png)

とは言っても、ちょっと前の書籍や動画などを見ると確かにやり方が違ったので、気になって調べた結果そういった事情がある事を知りました。
以降では、FlutterFire の仕組みを使って、Firebase を 紐付けする手順について解説していきます。

## ■ 連携手順

### 1. プロジェクト作成

まずは先に、[Firebase コンソール](https://console.firebase.google.com/u/0/?hl=ja)にアクセスして Project 作成しますので、「プロジェクトを追加」をクリック。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/76bfa8e4-c5cb-0285-2103-84667bd9c456.png)

任意の名前を決めて、実行します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/49b50ebc-4d37-75ab-2a71-dc9c49e5ed44.png)

Goole Analytics を有効にするか無効にするか選択してください。（デフォルトでは有効の様です）
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/a044c730-94ea-cfd8-a3da-d5de663b1e45.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/50823d83-b70d-b0f2-00fa-b8dd57d20904.png)

数十秒待機で、プロジェクトが作成されます。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/a8bdea18-477a-8465-aa14-590b6631d0a1.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/8b0e51ad-2cf1-ace7-dbf9-814b8a37b7c7.png)


### 2. firebase_core パッケージ（プラグイン）のインストール

firebase を使う為に必要なパッケージをインストールします。
ちなみにパッケージは下記です。（こういったパッケージは [**pub.dev**](http://pub.dev) というサイトで検索出来ます）
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/3a95f753-374c-9722-ef40-f9304b7b5a38.png)

- コマンド

```dart
% flutter pub add firebase_core
```

- 実行結果

```dart
% flutter pub add firebase_core
Resolving dependencies... 
  firebase_core 2.25.4 (from transitive dependency to direct dependency)
  flutter_lints 2.0.3 (3.0.1 available)
  js 0.6.7 (0.7.0 available)
  lints 2.1.1 (3.0.0 available)
  matcher 0.12.16 (0.12.16+1 available)
  material_color_utilities 0.5.0 (0.8.0 available)
  meta 1.10.0 (1.12.0 available)
  path 1.8.3 (1.9.0 available)
  test_api 0.6.1 (0.7.0 available)
  web 0.3.0 (0.5.0 available)
Changed 1 dependency!
9 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.
% 
```

上記コマンドを実行したら、pubspec.yaml に「firebase_core」が追加されているはずなので確認して下さい。
![99.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/b13568f7-4576-4131-d62f-12e5e7a41785.png)


### 3. Firebase CLI のインストール

次は、firebase コマンドを使えるようにしていきます。
インストール後、ちゃんとコマンドが使えるか Version で確認しています。

- コマンド

```dart
% sudo npm install -g firebase-tools
% firebase --version
```

- 実行結果

```dart
% sudo npm install -g firebase-tools                                                                          

added 641 packages in 27s

66 packages are looking for funding
  run `npm fund` for details
% 
% 
% firebase --version 
13.3.0
```

### 4. ログイン

先ほど Project を作ったのと同じ Google Account へログインします。

- コマンド

```dart
% firebase login
```

- 実行結果

```dart
% firebase login        
i  Firebase optionally collects CLI and Emulator Suite usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you.

? Allow Firebase to collect CLI and Emulator Suite usage and error reporting information? Yes
i  To change your data collection preference at any time, run `firebase logout` and log in again.

Visit this URL on this device to log in:
https://accounts.google.com/~~~~~~~~

Waiting for authentication...

✔  Success! Logged in as <Google Acount>
%
```

上記のコマンドを実行後、「Allow Firebase to collect CLI and Emulator Suite usage and error reporting information?」と聞かれるため、y を押下。(yes)
以下のようにブラウザが自動立ち上がり、Google Acount を選択する画面になる。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/6e4f1a5e-ec27-43d2-b8ed-4a230e39c724.png)
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/99de9d49-6bf4-f6f0-c266-9629f60e7db2.png)

以下の画像みたいに、「Firebase CLI Login Successful」になればログイン成功。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/ebe99c5b-ba06-d52d-715b-526c4fc79759.png)

### **5. FlutterFire CLI のインストールと利用手順**

FlutterFire のインストールして、パスを通して設定を反映してなどやってから、該当の Project へ接続していきます。
`flutterfire configure` コマンドを実行すると、現在ある Project が表示されますので選択 → プラットフォーム（android, ios, macos, web）の選択が表示されるので（デフォルトでは全部にチェックが入ってる）そのままで良ければ Enter → その後何か聞かれたら「y (yes) 」を押下でOKです。

- コード

```dart
// FlutterFire のインストール
% dart pub global activate flutterfire_cli
// パスを通す & zshrc に永続的に設定する
% echo 'export PATH="$PATH:$HOME/.pub-cache/bin"' >> ~/.zshrc
// 設定を反映させる
% source ~/.zshrc
// プロジェクトが一覧表示されるため、任意の Project を選択する
% flutterfire configure
```

- 実行結果

```dart
% dart pub global activate flutterfire_cli
+ ansi_styles 0.3.2+1s... (1.2s)
+ args 2.4.2
+ async 2.11.0
+ boolean_selector 2.1.1
+ characters 1.3.0
+ ci 0.1.0
+ cli_util 0.3.5 (0.4.1 available)
+ clock 1.1.1
+ collection 1.18.0
+ dart_console 1.2.0
+ deep_pick 0.10.0 (1.0.0 available)
+ ffi 2.1.0 (2.1.2 available)
+ file 6.1.4 (7.0.0 available)
+ flutterfire_cli 0.2.7
+ http 0.13.6 (1.2.1 available)
+ http_parser 4.0.2
+ interact 2.2.0
+ intl 0.18.1 (0.19.0 available)
+ json_annotation 4.8.1
+ matcher 0.12.16+1
+ meta 1.12.0
+ path 1.9.0
+ petitparser 6.0.2
+ platform 3.1.4
+ process 4.2.4 (5.0.2 available)
+ pub_semver 2.1.4
+ pub_updater 0.2.4 (0.4.0 available)
+ pubspec 2.3.0
+ quiver 3.2.1
+ source_span 1.10.0
+ stack_trace 1.11.1
+ stream_channel 2.1.2
+ string_scanner 1.2.0
+ term_glyph 1.2.1
+ test_api 0.7.0
+ tint 2.0.1
+ typed_data 1.3.2
+ uri 1.0.0
+ win32 5.2.0
+ xml 6.5.0
+ yaml 3.1.2
Building package executables... (2.0s)
Built flutterfire_cli:flutterfire.
Installed executable flutterfire.
Activated flutterfire_cli 0.2.7.
% 
% 
% echo 'export PATH="$PATH:$HOME/.pub-cache/bin"' >> ~/.zshrc
% 
% 
% source ~/.zshrc
% 
% 
% flutterfire configure
i Found 3 Firebase projects.                                                                                                                                                                                  
✔ Select a Firebase project to configure your Flutter application with · flutter-chatsns (flutter-chatsns)                                                                                                    
✔ Which platforms should your configuration support (use arrow keys & space to select)? · android, ios, macos, web                                                                                            
i Firebase android app com.example.chat_app registered.                                                                                                                                                       
i Firebase ios app com.example.chatApp registered.                                                                                                                                                            
i Firebase macos app com.example.chatApp.RunnerTests registered.                                                                                                                                              
i Firebase web app chat_app (web) registered.                                                                                                                                                                 
✔ Generated FirebaseAppID file /Users/firebase_app_id_file.json already exists, do you want to override it? · yes                                   
✔ Generated FirebaseOptions file lib/firebase_options.dart already exists, do you want to override it? · yes                                                                                                  
Unhandled exception:
FormatException: Unexpected end of input (at character 1)

^

#0      _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1383:5)
#1      _ChunkedJsonParser.close (dart:convert-patch/convert_patch.dart:501:7)
#2      _parseJson (dart:convert-patch/convert_patch.dart:36:10)
#3      JsonDecoder.convert (dart:convert/json.dart:610:36)
#4      FirebaseAndroidOptions.projectIdFromFileContents (package:flutterfire_cli/src/firebase/firebase_android_options.dart:29:29)
#5      FirebaseAndroidGradlePlugins.applyGoogleServicesPlugin (package:flutterfire_cli/src/firebase/firebase_android_gradle_plugins.dart:101:50)
<asynchronous suspension>
#6      FirebaseAndroidGradlePlugins.apply (package:flutterfire_cli/src/firebase/firebase_android_gradle_plugins.dart:240:5)
<asynchronous suspension>
%
```

正常に設定が完了すると、「lib/firebase_options.dart」というファイルが作成されます。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3282990/12382ab1-3aa1-8139-c25d-d3891fb88569.png)

### 6. Firebase の初期化

「main.dart」を以下の様に修正します。

- 変更前

```dart
void main() {
  runApp(MyApp());
}
```

- 変更後

```dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(MyApp());
}
```
    

インポートは以下の2つを追加する事で解決出来ます。

```dart
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
```

以上で設定は終わりなので、iOS / Android で正常にビルド出来るかテストしてみます。

ビルド出来なかった場合は、「**[パッケージの Version や Firebase などのアップデートによりエラーが出てしまった場合](https://qiita.com/tks_00/items/72f9f739c530f8924108#-%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE-version-%E3%82%84-firebase-%E3%81%AA%E3%81%A9%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%83%87%E3%83%BC%E3%83%88%E3%81%AB%E3%82%88%E3%82%8A%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%A6%E3%81%97%E3%81%BE%E3%81%A3%E3%81%9F%E5%A0%B4%E5%90%88)**」の対応が必要です。（実際に私が必要でした）

この辺りは Version や Firebase 側のアップデートによって、変わってしまいそうなので、上手くいかない場合は1回エラー文を見てみましょう。

## ■ パッケージの Version や Firebase などのアップデートによりエラーが出てしまった場合

### iOS のビルドが上手くいかない場合
iOS/Podfileの修正（依存関係やライブラリの集まりを指す言葉で、依存関係管理ツールとして使用されている）

1. 「platform :ios, '11.0'」のコメントアウトを外します。（この時のバージョンは是非エラー文を読んで欲しいです。◯◯以上にしてくれって書いてます。）

```dart
# Uncomment this line to define a global platform for your project
platform :ios, '11.0'
```

2. flutter clean を実行します。

```dart
% flutter clean
Cleaning Xcode workspace...                                      2,050ms
Cleaning Xcode workspace...                                      1,928ms
Deleting build...                                                  193ms
Deleting .dart_tool...                                               4ms
Deleting Generated.xcconfig...                                       0ms
Deleting flutter_export_environment.sh...                            0ms
Deleting Flutter.podspec...                                          0ms
Deleting ephemeral...                                                0ms
Deleting ephemeral...                                                0ms
Deleting ephemeral...                                                0ms
Deleting .flutter-plugins-dependencies...                            0ms
Deleting .flutter-plugins...                                         0ms
%
```

iOS/に移動して、podfile の update を実行します。

```dart
% cd ios
ios % 
ios % pod install --repo-update
Updating local specs repositories
Analyzing dependencies
cloud_firestore: Using Firebase SDK version '10.20.0' defined in 'firebase_core'
firebase_core: Using Firebase SDK version '10.20.0' defined in 'firebase_core'
Downloading dependencies
Installing BoringSSL-GRPC (0.0.24)
Installing Firebase (10.20.0)
Installing FirebaseAppCheckInterop (10.21.0)
Installing FirebaseCore (10.20.0)
Installing FirebaseCoreExtension (10.21.0)
Installing FirebaseCoreInternal (10.21.0)
Installing FirebaseFirestore (10.20.0)
Installing FirebaseFirestoreInternal (10.21.0)
Installing FirebaseSharedSwift (10.21.0)
Installing Flutter (1.0.0)
Installing GoogleUtilities (7.12.0)
Installing PromisesObjC (2.3.1)
Installing abseil (1.20220623.0)
Installing cloud_firestore (4.15.4)
Installing firebase_core (2.25.4)
Installing gRPC-C++ (1.49.1)
Installing gRPC-Core (1.49.1)
Installing leveldb-library (1.22.3)
Installing nanopb (2.30909.1)
Generating Pods project
Integrating client project
Pod installation complete! There are 3 dependencies from the Podfile and 19 total pods installed.

[!] `<XCBuildConfiguration name=`Debug` UUID=`331C8088294A63A400263BE5`>` attempted to initialize an object with an unknown UUID. `AE0B7B92F70575B8D7E0D07E` for attribute: `base_configuration_reference`. This can be the result of a merge and the unknown UUID is being discarded.

[!] `<XCBuildConfiguration name=`Release` UUID=`331C8089294A63A400263BE5`>` attempted to initialize an object with an unknown UUID. `89B67EB44CE7B6631473024E` for attribute: `base_configuration_reference`. This can be the result of a merge and the unknown UUID is being discarded.

[!] `<XCBuildConfiguration name=`Profile` UUID=`331C808A294A63A400263BE5`>` attempted to initialize an object with an unknown UUID. `640959BDD8F10B91D80A66BE` for attribute: `base_configuration_reference`. This can be the result of a merge and the unknown UUID is being discarded.

[!] `<PBXNativeTarget name=`RunnerTests` UUID=`331C8080294A63A400263BE5`>` attempted to initialize an object with an unknown UUID. `331C807E294A63A400263BE5` for attribute: `build_phases`. This can be the result of a merge and the unknown UUID is being discarded.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Runner` to `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` or include the `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` in your build configuration (`Flutter/Release.xcconfig`).
ios %
```

再度ビルドすると成功しました。

### Android のビルドが上手くいかない場合

以下の様にエラーが出た場合は、マルチデックス（Multidex）サポートを有効にする必要があります。

- エラー文

```dart
ERROR:D8: Cannot fit requested classes in a single dex file (# methods: 94121 > 65536)

[!] App requires Multidex support
Multidex support is required for your android app to build since the number of methods has exceeded 64k. See https://docs.flutter.dev/deployment/android#enabling-multidex-support for more information.
```

- 対処方法

build.gradle（モジュールレベル）の編集
`android/app/build.gradle` ファイル内の `android`**ブロック内にある**`defaultConfig`**セクションに**`multiDexEnabled true`を追加します。
```dart
android {
    defaultConfig {
        ...
        multiDexEnabled true
    }
    ...
}
```
    
依存関係の追加
次にプロジェクトの dependencies ブロックにマルチデックスライブラリを追加します。
```dart
dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
}
```

これで、メソッド数の制限を超える問題を解決出来るため、再度ビルドを行います。
それでも正常にビルドされない場合は、flutter clean をしてから再度ビルドを行う方法もあります。

## ■ **まとめ**

### 参考サイト

- 公式サイト（一次情報）

https://firebase.flutter.dev/docs/overview
    
    
- Firebase CLI リファレンス（一次情報）

https://firebase.google.com/docs/cli?hl=ja#install-cli-mac-linux
    
- Qiita や Zenn（二次情報）

https://qiita.com/kokogento/items/e4a587bebff32acb9489

https://zenn.dev/ryofrontenginer/articles/4c82457bb7408f    

### 補足
Firebase の Project 作成ですが、flutterfire configure コマンドを実行して「create a new project」を実行すれば、コマンドでも作成出来る様です。

ただ、Google analytics の設定がデフォルトだと無効になるみたいで、有効にしたい場合は Firebase 上で GUI 操作する必要がありそうなので今回は手順として外しましたがこういった方法もあるというのは記載しておきます。

```dart
% flutterfire configure
i Found 9 Firebase projects.                                                                                                                                                                                  
✔ Select a Firebase project to configure your Flutter application with · <create a new project>                                                                                                               
✔ Enter a project id for your new Firebase project (e.g. my-cool-project) · analytics-test-99                                                                                                                 
i New Firebase project analytics-test-99 created successfully.                                                                                                                                                
✔ Which platforms should your configuration support (use arrow keys & space to select)? · android, ios, macos, web                                                                                            
i Firebase android app com.example.chat_app is not registered on Firebase project analytics-test-99.                                                                                                          
i Registered a new Firebase android app on Firebase project analytics-test-99.                                                                                                                                
i Firebase ios app com.example.chatApp is not registered on Firebase project analytics-test-99.                                                                                                               
i Registered a new Firebase ios app on Firebase project analytics-test-99.                                                                                                                                    
i Firebase macos app com.example.chatApp.RunnerTests is not registered on Firebase project analytics-test-99.                                                                                                 
i Registered a new Firebase macos app on Firebase project analytics-test-99.                                                                                                                                  
i Firebase web app chat_app (web) is not registered on Firebase project analytics-test-99.                                                                                                                    
i Registered a new Firebase web app on Firebase project analytics-test-99.                                                                                                                                    
Unhandled exception:
FormatException: Unexpected end of input (at character 1)

^

#0      _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1383:5)
#1      _ChunkedJsonParser.close (dart:convert-patch/convert_patch.dart:501:7)
#2      _parseJson (dart:convert-patch/convert_patch.dart:36:10)
#3      JsonDecoder.convert (dart:convert/json.dart:610:36)
#4      FirebaseAndroidOptions.projectIdFromFileContents (package:flutterfire_cli/src/firebase/firebase_android_options.dart:29:29)
#5      FirebaseAndroidGradlePlugins.applyGoogleServicesPlugin (package:flutterfire_cli/src/firebase/firebase_android_gradle_plugins.dart:101:50)
<asynchronous suspension>
#6      FirebaseAndroidGradlePlugins.apply (package:flutterfire_cli/src/firebase/firebase_android_gradle_plugins.dart:240:5)
<asynchronous suspension>
%
%
% firebase projects:list                    
✔ Preparing the list of your Firebase projects
┌───────────────────────┬───────────────────────┬────────────────┬──────────────────────┐
│ Project Display Name  │ Project ID            │ Project Number │ Resource Location ID │
├───────────────────────┼───────────────────────┼────────────────┼──────────────────────┤
│ analytics-test-99     │ analytics-test-99     │ 233300629261   │ [Not specified]      │
└───────────────────────┴───────────────────────┴────────────────┴──────────────────────┘
1 project(s) total.
%
```