【Flutter×Firebase】Firebase周りをバージョンアップしたら意外と面倒だったので書き留めておく

##はじめに
Flutter×Firebaseでスマホアプリの個人開発をしているのですが、はじめてfirebaseのバージョンアップをしたところ、そこそこ苦労したので、流れをまとめておきます。

なにやらfirestoreの対応クエリが増えたという話を聞いたのがことの発端なのですが、そこはFlutterに関係あるのかよくわからず、無駄にバージョンアップだけしたという感じです。

##早速Firebaseのバージョンアップ
最新機能を使うために、まずはcloud_firestoreをバージョンアップ。

```pubspec.yaml
# 最新バージョンに変更
cloud_firestore: ^0.14.0+2
```

`pubspec.yaml` を書き換え、保存します。(VSCodeを使っているので、自動で`flutter pub get`)
 
ここでなにやらエラーメッセージが。
内容は割愛しますが、firebase_coreもバージョンアップする必要があるとのこと。
さらに、その他firebase関連もバージョンアップが必要だったので、最終的には以下のように、firebase関連を一通りバージョンアップすることになりました。

```pubspec.yaml
# それぞれ最新バージョンに変更
firebase_auth: ^0.18.0+1
firebase_core: ^0.5.0
firebase_storage: ^4.0.0
```

これで無事`flutter pub get`が通り、バージョンアップ自体は完了です。

##記法の変更が必要だった
ここで予期せぬ事態が発生。
これまで普通に動いていたコードがエラーになりました。
(バージョン変えたから当たり前ですかね・・・？　まだ駆け出しの自分にとっては想定外です)

さっきまで使っていたのは、`cloud_firestore: ^0.13.2`だったのですが、
そこからデータ取得の書き方が変更されていました。

まあ、VSCode上でカーソルをエラー箇所に合わせれば「こうしたらいいよ♪」っていうのを出してくれるので、そんなに大問題ではないんですけど・・・

一応コードの比較を載せておきます。

```^0.13.2
final newDocument =
        Firestore.instance.collection(getCollectionPath()).document();
    newDocument.setData(recruitment.toMap());
    return newDocument.documentID;
```

```^0.5.0
final newDocument =
        FirebaseFirestore.instance.collection(getCollectionPath()).doc();
    newDocument.set(recruitment.toMap());
    return newDocument.id;
```

`Firestore→FirebaseFirestore`
`document()→doc()`
`setData()→set()`
`documentID→id`

ざっとこんな感じでしょうか。
Flutter以外で使ったことがないのでなんともですが、ドキュメントをざっと見た感じだと、他言語の書き方に近くなったのかな？と思います。
(勘違いだったらすみません)

だいたいは、VSCode等の補完機能を使えば問題なく変換できたのですが、個人的にちょっとだけ苦戦したのが旧バージョンでの、`setDate(data, merge:true);`の既存データとマージする場合。
現行バージョンでは、以下のようになるので参考までに。

```dart

set(data, SetOptions(merge: true));
```

ちょっと面倒でしたが、対象箇所を全て書き換えてようやくエラー解消。

##あれ？まだエラーが残ってる
firestore周りを書き換えてOK!と思ったら、`firebase_auth`も変更が必要な部分がありました。

```dart

return FutureBuilder(
      future: FirebaseAuth.instance.currentUser(),  // ここでエラーが発生
      builder: (context, snapshot) {
       //(以下省略)
```
今度のエラーはなにやら、
`The expression doesn't evaluate to a function, so it can't be invoked`
う〜ん、、、ちょっと何言ってるかわかんないw

独学Flutter&駆け出しエンジニアで他言語の知見も浅い自分にとっては、即解決できない内容です。
(基本VSCode頼みなもので・・・)

たしか今までは、 `FirebaseAuth.instance.currentUser()`で`Future<FirebaseUser>`を返していたので、FutureBuilderを使っていい感じにしていたのですが(語彙力w)、現行バージョンだと`FirebaseAuth.instance.currentUser`で`User`を返す仕様になったみたいです。
(User=FirebaseUserかな？)

そこで単純に、

```dart

var currentUser = FirebaseAuth.instance.currentUser;
```
と書き換えてみたところ、まあ問題はなさそうです。

こんな感じで`firebse_auth`周りも修正したところで、エラーも消えてビルドが可能になりました。

##ビルド成功！、しかしまたエラー発生
無事ビルドが成功したのもつかの間、またまたエラーが発生しました。

内容は、`No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase`というもの。

はい、またわかりません。
ということでググってみると・・・

英語ですが、解決方法が見つかりました(以下参照)
https://stackoverflow.com/questions/63492211/no-firebase-app-default-has-been-created-call-firebase-initializeapp-in

初期化が必要だよ〜みたいなことを言っているらしく、

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // (以下省略)
```

↑のように書いていた`main.dart`を↓に書き換え

```main.dart

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   return FutureBuilder(                             // ここから
        future: Firebase.initializeApp(),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            throw Error();
          }
          if (snapshot.connectionState != ConnectionState.done)
            return Center(child: CircularProgressIndicator());   // ここまで追加
          return MaterialApp(
          // (以下省略)

```

`Firebase.initializeApp()`で初期化して、完了したら中身を表示するみたいなイメージでしょうか。
ともかく、このように書かないとうまく動かなかったです。 



##まとめ

ここまで修正して、ようやく今まで通り動作するようになりました。

ちなみにですが、ビルド時にios周りでもエラーが出ました。
ただ、基本は指示通りで解決できるので、ここでは割愛しています。
(問題ないはずなのにエラーが出る・・・という場合は、`flutter clear`→再ビルドがおすすめです。)

これまでプログラミング(アプリ開発)を学習する中で、バージョンを揃えることの重要性を耳にはしてきましたが、改めて、**「軽い気持ちでバージョンを変えると痛い目に合う」**ということを思い知りました。

Flutterはまだまだ日本語の情報が少なめなので、下手に最新のバージョンを使ったりすると痛い目に合うこともありますが、全体的にわかりやすく、開発はしやすいかなと思っています。

実際に駆け出しエンジニアの自分でも、そこそこ楽しく開発できているので、個人的におすすめです。
(Railsより楽しい！)


####最後に
私はまだエンジニア歴半年ほど&Flutterは独学なので、何かおかしい点やもっとこうした方がいいというご指摘があれば、コメントいただけると嬉しいです。

逆に、ここをもっと詳しく！といった質問もウェルカムです。

Flutter始めたての方や、英語が苦手で(私はGoogle翻訳に頼りまくってますw)日本語情報を探している方のお役に立てれば嬉しいです。