FlutterFireがアップデートしたからMigration Guideに沿って修正した記録

FlutterFire（FlutterでのFirebaseファミリー）がアップデートし、複数のFirebaseパッケージを使用していたので対応しなければならなくなりました。

アップデートすべきパッケージが多かったのと、破壊的変更があるとのことで身構えていました。
しかし、丁寧な公式ドキュメントもあり、僕の場合は問題なく追従することができました。

公式ドキュメント：[Migration Guide | FlutterFire](https://firebase.flutter.dev/docs/migration/)

なので、☝️のマイグレーションガイドを見るのが一番確実で分かりやすいと思います！
しかし、今回記録を取りながら対応したので備忘録としてここに残すことにしました。

## 環境
* Flutter: 1.20.2
* Xcode: 10.15
* Visual Studio Code: 1.48.0

## 各パッケージのアップデート
どのパッケージをどのバージョンにアップデートすべきかは[マイグレーションガイド](https://firebase.flutter.dev/docs/migration/)にハッキリと書かれているのでそれに合わせるだけでした。
一応、僕の環境ではこんな感じ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54170/5f3e5369-ecde-d7d2-dc4e-5e9a7d13a299.png" width=200>
※monoさんの `firestore_ref`を使わせていただいているので併せてアップデートしています。

## Androidのbuild.gradleを編集
`android/build.gradle`の`com.google.gms:google-services`のバージョンを最新化するように書いてあったため、3.2.1 を 4.3.3に修正しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54170/c1c2d5ed-74b8-53e2-c422-2a2249467a6a.png)

```android/build.gradle
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.3' // ここを変更！
        classpath 'io.fabric.tools:gradle:1.28.0' // Crashlytics
    }
```

## Firebaseの初期化処理を追加
Firebaseの各サービスを使う前に`Firebase.initializeApp()`を実行しておく必要があります。
僕は以下のように`runApp(Widget app)`前に、（非同期なので）await で実行するようにしました。

```dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Firebaseの各サービスを使う前に初期化を済ませておく必要がある
  await Firebase.initializeApp();
  runApp(const App());
}
```

monoさんに教えていただきましたが、公式のexampleでもそうしているようです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">それが一番良いと思います(　´･‿･｀)<a href="https://t.co/0vfo0GD0QM">https://t.co/0vfo0GD0QM</a> とかもそうなってますね(　´･‿･｀)</p>&mdash; mono (@_mono) <a href="https://twitter.com/_mono/status/1296931940314918913?ref_src=twsrc%5Etfw">August 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 実装コードの修正
### Firestore
#### Firestoreのインスタンスを取得する時の書き方が変わった。

```dart
// Before
Firestore.instance;
// After
FirebaseFirestore.instance;
```

#### スナップショット等の`data`がゲッターではなくメソッドになった。

```dart
// Before
snapshot.data;
// After
snapshot.data();
```

#### スナップショット等から取得する`documentID`が`id`という名前になった。

```dart
// Before
snapshot.documentID;
// After
snapshot.id;
```

#### アップデートのメソッド名が短くなった。

```dart
// Before
updateData(Map<String, dynamic> data);
// After
update(Map<String, dynamic> data);
```

#### `DocumentReference`を取得するメソッド名が短くなった。

```dart
// Before
document([String path]);
// After
doc([String path]);
```

#### `List<QueryDocumentSnapshot>`を取得するゲッター名が短くなった。

```dart
// Before
List<QueryDocumentSnapshot> get documents
// After
List<QueryDocumentSnapshot> get docs
```

#### set の `merge` パラメータがSetOptionsを使うようになった。

```dart
// Before
setData(Map<String, dynamic> data, [Bool merge])
// After
set(Map<String, dynamic> data, [SetOptions options])
// e.g.
.set(
  data,
  SetOptions(merge: true),
)
```

### Authentication
#### サインイン中ユーザーを取得するメソッドがゲッターになり、非同期ではなくなった。

```dart
// Before
await FirebaseAuth.instance.currentUser();
// After
FirebaseAuth.instance.currentUser;
```

一見、非同期ではなくなり嬉しいのですが、注意点もあるそうです。僕もアプリ起動時にサインイン状態かを判定しているので、ここの挙動は注意深く見ていきたいと思います🙏
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">扱いにくいという意見をちょくちょく見かけるWebのSDKに合わせられてしまったので、「便利になって嬉しい」と単純に書き換えると危険なことがある。<br>例えば起動直後にアクセスしてnullだった場合、未ログインなのかまだ内部的な更新処理が終わってないだけなのか分からない。<a href="https://t.co/oYXxS4GlDr">https://t.co/oYXxS4GlDr</a> <a href="https://t.co/2JMFtQFxFi">https://t.co/2JMFtQFxFi</a> <a href="https://t.co/yu1b8RVOR4">pic.twitter.com/yu1b8RVOR4</a></p>&mdash; mono (@_mono) <a href="https://twitter.com/_mono/status/1296061466630475779?ref_src=twsrc%5Etfw">August 19, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#### ユーザーの型名が`User`になった。

```dart
// Before
FirebaseUser
// After
User
```

#### `onAuthStateChanged` ゲッターが`authStateChanges`メソッドになった。

```dart
// Before
onAuthStateChanged;
// After
authStateChanges();
```

#### `userChanges`が追加された。
https://pub.dev/documentation/firebase_auth/latest/firebase_auth/FirebaseAuth/userChanges.html
`onAuthStateChanged`がユーザーのサインイン状態（サインインやサインアウトなど）の変更についてだけ通知するのに対して`idTokenChanges`の機能も含んだスーパーセットということでしょうかね？

```dart
// 使用例
_auth.userChanges().listen((user) {
  state = user;
});
```

#### AuthResultの型名が変更された。

```dart
// Before
AuthResult
// After
UserCredential
```

#### `OAuthProvider`が引数名なしになった。

```dart
// Before
OAuthProvider({String providerId})
// After
OAuthProvider(String providerId)
```

#### `getCredential`のメソッド名から`get`がなくなった。

```dart
// Before
getCredential({String accessToken, String idToken, String rawNonce})
// After
credential({String providerId})
```

#### `unlinkFromProvider`のメソッド名が短くなった。

```dart
// Before
unlinkFromProvider(String providerId)
// After
unlink(String providerId)
```

## FirestoreWeb も FirebaseFirestoreWeb に

```dart
// Before
FirestoreWeb
// After
FirebaseFirestoreWeb
```

以上は僕が対応必要だったところだけ書き残しただけなので、実際にはもっとたくさんの変更があります。
[Migration Guide | FlutterFire](https://firebase.flutter.dev/docs/migration/)にすべて書いてありますので上から順に対応していくのが良いかと思います！

ご閲覧ありがとうございました！