[Flutter] Flutterプロジェクト用にFirebaseを設定する

# はじめに
こんにちは、未経験/独学からフロントエンドエンジニアとしての就職を目指しているYuuhaと申します。

前回、前々回とデスクトップアプリ、Webアプリを制作したので、次はモバイルアプリに触れてみようと思い、実際のアプリ制作を通してFlutterについて学習しました。

今回は、Flutterプロジェクト用にFirebaseの初期設定を行う方法と、Firebaseで基本的に出来ることをメインに解説していきます。Firebaseに触れるのが初めてだったので、最初に公式ドキュメントを見たとき「？」となったところを備忘録的にまとめておこうかと思います。

# 制作したもの
とりあえずYoutubeのクローンアプリを制作してみました。

https://github.com/ds-yuuha/movietube/tree/master

# Firebase CLIのインストール
まず、FirebaseをFlutterプロジェクトへ追加するために、Firebaseのコマンドラインインターフェース(CLI)をnpmでインストールします。

公式ドキュメント曰く、Firebase CLI を使用するには、Node.js v18.0.0 以降が必要だそうなので、Node.jsのバージョンは新しいものにしておきましょう。

あと、注意としてコマンドプロンプトだと実行できない場合などがあるみたいです。確か、僕もVS Code上だと上手く行かなかった気がします。
調べてみると、実行ポリシーの変更やパスを通すなどの解決策が出てきました。実行ポリシーの変更はあまり触りたくなかったのでやりませんでした。パスを通す解決策を試してみても上手く行きませんでした。
PowerShellでやれば上手くいくとのことだったので、結局PowerShell上で実行したら問題なくインストールされました。

```
npm install -g firebase-tools
```

これで、firebaseコマンドが使用可能になります。次に、Firebaseアカウントを作成しておきましょう。
アカウントを作成した状態で、以下のコマンドを入力してログインします。

```
firebase login
```

アカウントにログイン成功した場合は、下のコマンドを打つと、Firebaseで作成しているプロジェクト名の一覧が表示されるようになります。

```
firebase projects:list
```

次に、Flutterプロジェクト上でFirebaseを初期化します。プロジェクトディレクトリを作成、もしくは既にプロジェクトディレクトリがあるなら、そのディレクトリに移動し以下のコマンドを入力してください。

```
firebase init
```

これにより、firebase.jsonファイルが作成されます。
あとは、以下のコマンドを入力すれば、Firebase CLIがインストールされるはずです。

```
dart pub global activate flutterfire_cli
```

# Firebaseの初期設定
プロジェクトディレクトリで以下コマンドを入力すると、アプリの構成が開始されます。
```
flutterfire configure
```

これで、基本的にFlutter上でFirebaseが利用できるようになったので、あとは必要なものをインストールしていきます。

```
flutter pub add firebase_core
```
```
flutterfire configure
```

上記はFirebaseのコアプラグインをインストールしています。新しいプラグインをインストールしたら、再度configureコマンドでアプリの構成を更新しておきましょう。

# Firebaseでよく使われるであろうプラグイン
プラグインは必要に応じて以下のコマンドでインストールします。
先述のように、プラグインを導入したらconfigureしておきましょう。

```
flutter pub add "プラグイン名"
```
今回のアプリ制作でも使ったプラグインとその機能を紹介します。

| プラグイン名 | 基本的な機能 |
|:-:|:-:|
| firebase_auth | ログイン・ユーザーの管理などの認証機能を利用できます |
| cloud_firestore | Firebaseのデータベース/リアルタイムで変更が反映され、後述のfirebase_databaseと違い、データに階層構造をもつ |
| firebase_storage | 写真や動画などのコンテンツを保管するストレージ |
| firebase_database | こちらもFirebaseのデータベース/階層構造を持たず、こちらはインポート・エクスポート機能をもつ |

# FlutterでFirebaseの機能を利用する
FlutterでFirebaseを利用する準備が完了したら、あとはimport文で読み込んできて使用するだけです。
まずは、main.dartに基礎となるfirebase_coreを読み込んでおきます。

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

他の機能(プラグイン)に関しても同様なので、サインイン機能を例を以下に示します。
awaitの後に続く一文はFirebaseを利用するための初期化処理です。今回は、providerで認証状態の変化を管理しています。

```dart: main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'services/auth_service.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => AuthService()),
      ],
      child: const MyApp(),
    ),
  );
}
```

```dart: auth_service.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/user_model.dart';

class AuthService with ChangeNotifier {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  User? get currentUser => _auth.currentUser;
  Stream<User?> get authStateChanges => _auth.authStateChanges();

  // Sign in with email and password
  Future<UserCredential> signIn(String email, String password) async {
    BuildContext? context;
    try {
      UserCredential userCredential = await _auth.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
      notifyListeners();
      return userCredential;
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        ScaffoldMessenger.of(
          context!,
        ).showSnackBar(SnackBar(content: Text('そのメールアドレスは登録されていません')));
      } else if (e.code == 'wrong-password') {
        ScaffoldMessenger.of(
          context!,
        ).showSnackBar(SnackBar(content: Text('パスワードが間違っています')));
      }
      rethrow;
    }
  }
}
```

以上のように、Firebaseインスタンスから必要なメソッドを呼び出していくのが基本的な使用法になります。
上のauth_serviceでは、try文を使用してsignInWithEmailAndPassword()メソッドを呼び出し、成功すればnotifyListeners()で変化を通知、ユーザー情報であるuserCredentialを返す、エラーが発生した場合、そのエラーを表示するというメソッドを定義しています。
また、サインイン処理以外にもユーザー登録や退会処理なども定義しておけば、自由に呼び出してくることが可能です。

# まとめ
以上、FlutterでFirebaseを利用するための初期設定と簡易的な使用法の解説でした。
Firebaseのように既存のBaaSを利用することで、個人でも比較的簡単にYoutubeクローンアプリのようなものが作れるというのは、フロントエンドを中心に学ぶものとしてはありがたいことです。

# おまけ
### 作ったYoutubeクローンアプリの紹介
セキュリティ的な観点からアプリ自体は公開していないので、ここで少しだけアプリの紹介をしておきたいと思います。機能面は大体自分で書きましたが、UI部分はAI(Claude)に任せました

### ホーム画面

![1000000041.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/4bacfc72-8c36-49df-8901-d49beb0c0458.png)

### 再生画面
再生用のスライダーやチャンネル登録・解除機能なども実装しています

![1000000042.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/9abb3712-3bc8-42e0-91ce-2b640448069c.png)

### 登録チャンネル画面
登録しているチャンネルをここで表示しています

![1000000043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/98b55eda-61d0-47d8-ad88-726039049804.png)

### マイページ
一応、プロフィール編集ができます

![1000000044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/f5c6a541-ef2d-426c-ae60-dcabd72a0bd5.png)

### 動画投稿画面
サムネイルと動画、タイトル、概要欄、タグを設定できます

![1000000045.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/c2790cdf-a323-4bed-8cea-d6fcb245be12.png)

### コメント画面
コメントを動画ごとに送信できます

![1000000046.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4030186/aae788fd-69d5-4cff-8e50-191d81553fd1.png)

以上、アプリの紹介でした。まだまだ拙い出来ではありますがいろいろな勉強になったのでヨシとします。それでは、また次回。