Flutter×Firebase1_FlutterアプリにFirebaseを追加【Mac】

いやーーー今週はエラーに悩まされました:sob:
まだ解決してませんが
おそらく個人的なエラーと認識できたので投稿します！

Flutter関連の投稿です。

備忘録として使用する予定ですが
皆さんの解決策にもなれば幸いです。
今回からはFirebaseの投稿になります。

今回はFlutterアプリにFirebaseを追加します！
またページ内リンクや注釈を加えましたので
以前より説明が分かりやすく
ページ内遷移も楽になったと思います。

## 目次
[-完成イメージ](#完成イメージ)
[-1.構成](#1構成)
[-2.FlutterアプリにFirebaseを追加①_main.dartの整理](#2flutterアプリにfirebaseを追加_maindartの整理)
[-3.FlutterアプリにFirebaseを追加②_ターミナルからFirebaseへログイン・FlutterFireCLIのインストール](#3flutterアプリにfirebaseを追加_ターミナルからfirebaseへログインflutterfirecliのインストール)
[-4.FlutterアプリにFirebaseを追加③_Firebase上にプロジェクトを作成・プロジェクトの連携](#4flutterアプリにfirebaseを追加_firebase上にプロジェクトを作成プロジェクトの連携)
[-5.FlutterアプリにFirebaseを追加④_プロジェクト連携後の追加処理](#5flutterアプリにfirebaseを追加_プロジェクト連携後の追加処理)
[-6.FlutterアプリにFirebaseを追加⑤_FireStoreのインストール](#6flutterアプリにfirebaseを追加_firestoreのインストール)
[-7.FlutterアプリにFirebaseを追加⑥_FireStoreを導入する](#7flutterアプリにfirebaseを追加_firestoreを導入する)
[-8.FlutterアプリにFirebaseを追加⑦_Firebase上でデータを登録する](#8flutterアプリにfirebaseを追加_firebase上でデータを登録する)
[-9.全体コード](#9全体コード)
[-参考文献](#参考文献)
[-最後に](#最後に)


## 完成イメージ
・FlutterアプリにFirebaseを追加
・Firebaseより本一覧を記入

<img width="40%" alt="firebase_add③.png" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/71346e92-aafd-eb53-ddb4-946cede222f4.png">


## 1.構成
・main.dartのコードを整理をし、book_list_page.dartを作成
・ターミナルからFirebaseのツールをインストールしログインする
・FlutterFireCLIをインストールする
・Firebase上にプロジェクトを作成し、開発中のプロジェクトを
　flutter configureで連携させる
・flutter pub add firebase_coreを行う
・構成ファイルと初期化処理を追加する
・flutter pub add cloud_firestoreでFireStoreをインストールする
・book_list_page.dartにFireStoreを導入する
・Firebase上でデータを登録する


## 2.FlutterアプリにFirebaseを追加①_main.dartの整理
・main.dartのコードを整理をし、book_list_page.dartを作成する
```php:main.dart
import 'package:firebase1_firebase_add/book_list_page.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BookListSample',
      home: BookListPage(),
    );
  }
}
```

```php:book_list_page.dart
import 'package:flutter/material.dart';

class BookListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text('本一覧'),
      ),
      body: Center(
        child: Text(
          ‘本一覧’,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: null,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
```
<img width="30%" alt="firebase_add①.png" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/5dc205b6-6423-2511-7942-eee16599748b.png">
※現状のイメージ画像

## 3.FlutterアプリにFirebaseを追加②_ターミナルからFirebaseへログイン・FlutterFireCLIのインストール
・ターミナル[^1]からFirebaseをインストールする
[^1]:Macのホーム画面右上にある🔍ボタンを押し
「ターミナル」と入力すると黒い画面が出現します。

```php:terminal
curl -sL https://firebase.tools | bash
```
・Firebaseにログインする
・質問文に対してY/nで聞かれるのでYを入力する
```php:terminal
firebase login
```
・FlutterFireCLIをインストールする
```php:terminal
dart pub global activate flutterfire_cli
```



## 4.FlutterアプリにFirebaseを追加③_Firebase上にプロジェクトを作成・プロジェクトの連携
・下記リンクにログインする
　<font color="Red">※ログインは先ほどログインしたものと同様のアカウント</font>
　https://firebase.google.com/
・右上の「Go to Console」をクリック
・「プロジェクトを追加」をクリック
・プロジェクト名を記入する→続行
![firebase_add④.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/24562e43-d93f-e36f-11b2-21972f6beb55.png)

・Googleアナリティクスアカウントを選択→プロジェクト作成
　※何もお持ちでない方は「Default Account for Firebase」を選択
![firebase_add⑤.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/c0b6873d-2b1d-f3d3-fdd9-b709a0537df4.png)
Firebase上はこれでOK！！！


・プロジェクト内のターミナル[^2]で
　Firebaseが使用できるように構成する
[^2]:Android StudioやVScode内にあるターミナルを使用
```php:your project's terminal
flutter configure
```
・作成したプロジェクトを選択してEnterを押す
<img width="50%" alt="firebase_add⑥.png" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/d2362a72-11ea-11fe-3dd5-b9d0f4d529a7.png">

・使用するプラットフォーム（ios、android、webなど）を選択する
　※スペースキーで外したり選択が可能。
 　　基本iosとandroidのみでOK
 <img width="50%" alt="firebase_add⑦.png" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/9ac31a59-7423-e49b-a2ed-063e4fd9350f.png">

libフォルダ内にfirebase_options.dartがあればOK！！！
![firebase_add⑧.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/5de7165f-9889-2ccc-2c3f-893302cbf011.png)


## 5.FlutterアプリにFirebaseを追加④_プロジェクト連携後の追加処理
・プロジェクト内のターミナル[^3]でFlutterアプリのFirebase構成を最新にする
[^3]:Android StudioやVScode内にあるターミナルを使用

```php:your project's terminal
flutter pub add firebase_core
```
pubspec.yamlに下記表示があればOK！！！
firebase_options.dartのimportのエラーも解消される

```php:pubspec.yaml
  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  firebase_core: ^3.1.0//←この表記があればOK！！！
```

・main.dartに構成ファイルと初期化処理を追加する
```main.dart
import 'package:firebase1_firebase_add/book_list_page.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';//←構成ファイルの追加
import 'firebase_options.dart';//←構成ファイルの追加

void main() async {//←初期化処理のためasyncを追加
  WidgetsFlutterBinding.ensureInitialized();//←初期化処理の追加

  await Firebase.initializeApp(//←初期化処理の追加
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

```



## 6.FlutterアプリにFirebaseを追加⑤_FireStoreのインストール
・プロジェクト内のターミナル[^4]で
　FlutterアプリにFireStoreをインストールする
[^4]:Android StudioやVScode内にあるターミナルを使用

```php:your project's terminal
flutter pub add cloud_firestore
```
pubspec.yamlに下記表示があればOK！！！
```php:pubspec.yaml
  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  firebase_core: ^3.1.0
  cloud_firestore: ^5.0.1//←この表記があればOK！！！
```


## 7.FlutterアプリにFirebaseを追加⑥_FireStoreを導入する
・book_list_page.dartのCenter Widget内に
　Streambuilder<>〜を記載する
・final Stream<QuerySnapshot> _usersStreamを追加

```php:book_list_page.dart
class BookListPage extends StatelessWidget {
  final Stream<QuerySnapshot> _usersStream =
      FirebaseFirestore.instance.collection('books').snapshots();//←追加

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text('本一覧'),
      ),
      body: Center(
        child: StreamBuilder<QuerySnapshot>(
          stream: _usersStream,
          builder:
              (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Text("Loading");
            }

            return ListView(
              children: snapshot.data!.docs.map((DocumentSnapshot document) {
                Map<String, dynamic> data =
                    document.data()! as Map<String, dynamic>;
                return ListTile(
                  title: Text(data['title']),
                  subtitle: Text(data['author']),
                );
              }).toList(),
            );
          },
        ),
      ),//←//Center内にStreambuilder<>〜を追加
      floatingActionButton: FloatingActionButton(
        onPressed: null,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
```


## 8.FlutterアプリにFirebaseを追加⑦_Firebase上でデータを登録する
・下記リンクにログインする
　<font color="Red">※ログインは先ほどログインしたものと同様のアカウント</font>
　https://firebase.google.com/
・右上の「Go to Console」をクリック
・作成したプロジェクトをクリック
・左のタブの「構築」→「Firestore Database」をクリック
 <img width="30%" alt="firebase_add⑨.png" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/dd5f208b-8bd2-6b97-2449-0261a7c62aae.png">

・「コレクションを開始」をクリック
・コレクションIDに「books」→次へ
・ドキュメントIDの「自動ID」をクリック
・フィールドに「title」、値に「エコノミー革命」を入力
・フィールドの追加→フィールドに「author」、
　値に「尾原　和啓」を入力
 
<img width="70%" alt="firebase_add⑩_GIF.gif" img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121562/7170e8ba-5e1e-7e69-c981-ed21a5e64ad1.gif">
<font color="Red">

※2回目以降の入力は、「ドキュメントを追加」をクリックして
　authorとtitleのみを入力する</font>

これで完成！！！

## 9.全体コード
```php:main.dart
mport 'package:firebase1_firebase_add/book_list_page.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BookListSample',
      home: BookListPage(),
    );
  }
}
```
```php:book_list_page.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class BookListPage extends StatelessWidget {
  final Stream<QuerySnapshot> _usersStream =
      FirebaseFirestore.instance.collection('books').snapshots();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text('本一覧'),
      ),
      body: Center(
        child: StreamBuilder<QuerySnapshot>(
          stream: _usersStream,
          builder:
              (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Text("Loading");
            }

            return ListView(
              children: snapshot.data!.docs.map((DocumentSnapshot document) {
                Map<String, dynamic> data =
                    document.data()! as Map<String, dynamic>;
                return ListTile(
                  title: Text(data['title']),
                  subtitle: Text(data['author']),
                );
              }).toList(),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: null,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

```
```php:firebase_options.dart
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, kIsWeb, TargetPlatform;

/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
///   options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      throw UnsupportedError(
        'DefaultFirebaseOptions have not been configured for web - '
        'you can reconfigure this by running the FlutterFire CLI again.',
      );
    }
    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return android;
      case TargetPlatform.iOS:
        return ios;
      case TargetPlatform.macOS:
        throw UnsupportedError(
          'DefaultFirebaseOptions have not been configured for macos - '
          'you can reconfigure this by running the FlutterFire CLI again.',
        );
      case TargetPlatform.windows:
        throw UnsupportedError(
          'DefaultFirebaseOptions have not been configured for windows - '
          'you can reconfigure this by running the FlutterFire CLI again.',
        );
      case TargetPlatform.linux:
        throw UnsupportedError(
          'DefaultFirebaseOptions have not been configured for linux - '
          'you can reconfigure this by running the FlutterFire CLI again.',
        );
      default:
        throw UnsupportedError(
          'DefaultFirebaseOptions are not supported for this platform.',
        );
    }
  }

  static const FirebaseOptions android = FirebaseOptions(
    apiKey: 'your api key',
    appId: '1:481769511549:android:2c0a8fbf00cc7a42016f14',
    messagingSenderId: '481769511549',
    projectId: 'book-list-sample-f1449',
    storageBucket: 'book-list-sample-f1449.appspot.com',
  );

  static const FirebaseOptions ios = FirebaseOptions(
    apiKey: 'your api key',
    appId: '1:481769511549:ios:dbae2200057f984c016f14',
    messagingSenderId: '481769511549',
    projectId: 'book-list-sample-f1449',
    storageBucket: 'book-list-sample-f1449.appspot.com',
    iosBundleId: 'com.example.firebase1FirebaseAdd',
  );
}
```
pubspec.yamlは変更点のあった35~39行目付近のみを記載
```php:pubspec.yaml
  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  firebase_core: ^3.1.0
  cloud_firestore: ^5.0.1
```

## 参考文献
Flutter大学. 「【2021年8月最新】FlutterアプリにFirebaseを追加しよう」.　YouTube.　2021/07,https://www.youtube.com/watch?v=VZ9wcJ920XA&t=0, (参照 2024-06-30)

Flutter大学. 「【Flutter×Firebase2024】Firebase接続とエラー解消」.　YouTube.　2024/06,https://www.youtube.com/watch?v=DxO_uxnTRSE&t=0, (参照 2024-06-30)

Firebase. 「Flutter アプリに Firebase を追加する」. 2024,
https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios, (参照 2024-06-30)

Firebase. 「Firebase CLI リファレンス」. 2023,
https://firebase.google.com/docs/cli?hl=ja&_gl=1*1schew5*_up*MQ..*_ga*OTQxMDY0NTU3LjE3MTk3MjYyMjc.*_ga_CW55HF8NVT*MTcxOTcyNjIyNi4xLjAuMTcxOTcyNjIyNi4wLjAuMA..#install-cli-mac-linux, (参照 2024-06-30)

Firebase. 「Cloud Firestore を使ってみる」. 2024,
https://firebase.google.com/docs/firestore/quickstart?hl=ja&_gl=1*1hiohbj*_up*MQ..*_ga*OTQxMDY0NTU3LjE3MTk3MjYyMjc.*_ga_CW55HF8NVT*MTcxOTcyNjIyNi4xLjAuMTcxOTcyNjIyNi4wLjAuMA..#dart, (参照 2024-06-30)




## 最後に
・現在発生しているエラーは
　Androidでエミュレータが起動しない問題です
　こちらでもし同様の現象となればご連絡頂けたらと思います。
・2024版と2021年版を参考にしています
　2024年版ではFireStoreサイト上でiOSとAndroidの
 　登録がなくなっておりました。
・全体コードは今後多くなってくる場合は
　変更点のみ記載しようかと考えております。
・同じ注釈はまとめてもいいかなーとも思いました！