FlutterをFirebaseに連携する仕様が変わっていてハマったのでメモ

# はじめに
自分で構築した機械学習モデルを自分のスマホで使用するために趣味がてら取っつきやすそうなFlutterをUdemyの一番人気の[Flutter & Dart - The Complete Guide [2023 Edition]](https://www.udemy.com/course/learn-flutter-dart-to-build-ios-android-apps/)を通じて勉強しています。
Udemy講義の中でFlutterのVersionを落とすように言っているのですが、せっかくだから最新の`Flutter 3.7.3`でやりたいと意地を張っていたらハマったので解決方法をQiitaにメモっとこうと思いました。

## 1. ハマりポイント1
Udemyの講義で使っていた`Firestore Class`がdeprecatedされていました。
`Firestore Class`がだめなら、`FirebaseFirestore Class`に差し替えれば動くでしょと安易に思ったらエラーが出てきました。
具体的な内容は忘れましたが、FlutterFireをInitializeしろと怒られました。

## ハマりポイント2
[Initializing FlutterFire](https://firebase.flutter.dev/docs/overview#initializing-flutterfire)で、丁寧にFlutterFireのInitializeのやり方があったので、書いてあることをそのまま実行しました。が、以下のところで別のエラー。

```powershell
# Run the `configure` command, select a Firebase project and platforms
flutterfire configure
```
`FirebaseCommandException: An error occured on the Firebase CLI when attempting to run a command.`
文字通り、Firebase CLIを入れればいいのかと思い、[公式](https://firebase.google.com/docs/cli)に従いインストール。
ここでも、自パソコンにNode.jsを入れてなかったので`standalone binary`をそのままWindowsに落としたらPATHがなぜか通らなかったので結局`Node.js`を落としてから`npm`でインストールする二度手間もありました。

## ハマりポイント2 追記

後日新しくプロジェクトを作り`flutterfire configure`を実行したところ、以下のエラーが出ました。
```powershell
FirebaseCommandException: An error occured on the Firebase CLI when attempting to run 
COMMAND: firebase projects:list --json
```
察するに、何らかの原因でFirebaseのプロジェクトにアクセスできなかったようです。
以下のコマンドを実行し、CLIでFirebaseに入りなおしたところ解消できました。
```powershell
firebase login --reauth
```

## ハマりポイント3
[Initializing FlutterFire](https://firebase.flutter.dev/docs/overview#initializing-flutterfire)に戻り、`main.dart`を直したところで、`FirebaseFirestore Class`からデータ取れるでしょと思ったら、だめでした。
Udemyを元にしたコードで、Firestoreのデータを取ろうとしている箇所は以下です。

```dart
//UdemyのCode
FirebaseFirestore.instance
    .collection('chats/d6J4hnZnvm8dS5fndoHG/messages')
    .snapshots()
    .listen((data) {
  print(data.documents[0]['text']);
});
```

`data`の`QuerySnapshot Class`に`documents`がありませんでした。`docs`が代わりにあったので、特に調べもせず`docs`に変えて実行。
```dart
//UdemyのCode
FirebaseFirestore.instance
    .collection('chats/d6J4hnZnvm8dS5fndoHG/messages')
    .snapshots()
    .listen((data) {
  print(data.docs[0]['text']);
});
```
これで値が取れました。

## ハマりポイント4
Udemyの`documents`を`docs`に変更する前に、もう１ハマりありました。なぜか、公式サイトに従ったデータの取り方をすべきでしょというDeveloper気質を急に発揮し、コードを大きく変えたところハマりました。
ハマった時のコードは修正して持ち合わせていないのですが、自分がやってしまったのは
```dart
final docRef = FirebaseFirestore.instance
    .collection('chats/d6J4hnZnvm8dS5fndoHG/messages')
.doc();
```
と、`doc()`にPATHを指定せずに書いていたことです。
    `DocumentReference Class`について`If no [path] is provided, an auto-generated ID is used.`とあったので勘違いしていました。


```dart
final docRef = FirebaseFirestore.instance
    .collection('chats/d6J4hnZnvm8dS5fndoHG/messages')
    .limit(1);

docRef.get().then(
  (querySnapshot) {
    final doc = querySnapshot.docs.first;
    final data = doc.data() as Map<String, dynamic>;
    print(data['text']);
    // ...
  },
  onError: (e) => print("Error getting document: $e"),
);
}),
```
のように`limit(1)`で最初のDocumentを無事取得できました。
ちなみに`limit(1)`のやり方はChatGPTに教わりました。

## 最後に
公式以外の情報は古いことがほとんどなので、あまり参考にしませんでした。[Migration Guide](https://firebase.flutter.dev/docs/migration/)によると、どうやら2020年にFlutterとFirebaseの連携作法が変わったようです。
FlutterのFirebase周りに関するバグ解決は公式サイトとChatGPTだけを頼りにした方が、効率はよさそうな印象を受けました。ChatGPTはたまに嘘つきますけどね。