Open4

Dynamic Linksが使えなくなるけど、メール認証新規登録はしたい【Flutter×Firebase】

FBD TechFBD Tech

Dynamic Linksが使えなくなる!

Firebase Dynamic Links は非推奨となっており、このリンクがまだ使用されていないプロジェクトでは採用しないでください。サービスは 2025 年 8 月 25 日に廃止されます

ということで、Dynamic Linksを使わずにメール認証新規登録をする方法を模索してみました

ちなみに、Firebase AuthenticationDynamic Linksは引き続き使えるのがミソです

Q. Firebase Authentication でのみ Dynamic Links を使用しています。Firebase Authentication のメールリンク認証は引き続き機能しますか?
はい。Firebase Authentication を使用したメールリンク認証は引き続き機能します。 Firebase Authentication は現在、Firebase Dynamic Links を使用して Authentication リンクをカスタマイズしていますが、Firebase Dynamic Links サービスが終了した後もこの機能が引き続き動作するように、更新を提供いたします。

sendSignInLinkToEmailの謎挙動

パスワードリセットやパスワード変更、currentUserがある場合のメール認証(currentUser.sendEmailVerification)はWeb上で完結する機能がFirebaseに用意されている。
だから用意されているメソッドを叩くだけでいい。
でもなぜか、sendSignInLinkToEmailで送信されるURLはDynamic Linksだし、Web上で処理してくれない(ローディングして、なんか処理してる風だけどなにもしてない?mode=signinになってるのになにもしないという謎)
そのため、処理は自分で書く必要がある。
公式でもアプリで処理してね、とのこと。

Firebase Authentication は、Firebase Dynamic Links を使用してモバイル デバイスにメールリンクを送信します。モバイルアプリ経由でログインを行う場合、リンクの受信を検出し、ディープリンクを解析してログインを完了するようにアプリを構成する必要があります。

というわけで進めます。

FBD TechFBD Tech

設定はこれだけ

とりあえず、これの通りやればいいのですが、最低限忘れがちなのをメモします。

Firebase コンソールでDynamic Linksを有効化する

Dynamic Linksは使えなくなるのですが、なぜかDynamic Linksを有効にしないとそもそもメール認証時にエラーが返ってきます。謎です。

FirebaseにApp Store IDとチーム IDを設定する

Firebaseのプロジェクトの設定 > 全般 > マイアプリ > Appleアプリの設定を忘れないように。
デフォルトで設定不要だけど必要。
もちろんApple Store IDはApple Store Connectからアプリ作らないとダメ。

info.plistでFirebaseDeepLinkPasteboardRetrievalEnabledをONにしない

変な挙動になります。OFFにするかそもそも書かなくてOK!

作ったDynamic LinksをAssociated Domainsにいれる

FBD TechFBD Tech

コードを書く

Flutterを書いていきます

uni_linksを入れる

これ!
https://pub.dev/documentation/uni_links/latest/

コードはこれだけ!

// importは省略

  final FirebaseAuth _auth = Firebase.auth;
  StreamSubscription? _uniLinksListener;

  Future<void> signupWithEmail({required String email}) async {
    try {
      final actionCodeSetting = ActionCodeSettings(
        url: {ACTION_CODE_URL}, // Webに飛んだ場合の最終リダイレクトURL(アプリのみで認証するなら、スマホで開いてくださいとかアラーとするのもあり?)
        iOSBundleId: {IOS_BUNDLE_ID},
        handleCodeInApp: true,
        androidPackageName: {ANDROID_PACKAGE_NAME},
        androidInstallApp: true,
        androidMinimumVersion: '12',
      );
      await _auth.sendSignInLinkToEmail(email: email, actionCodeSettings: actionCodeSetting);
      _uniLinksListener = linkStream.listen((uri) async {
        try {
          await _auth.signInWithEmailLink(email: email, emailLink: link);
          if (_uniLinksListener != null) {
            _uniLinksListener?.cancel();
            _uniLinksListener = null;
          }
        } on AppException {
          rethrow;
        }
      });
    } on AppException {
      rethrow;
    }
  }

ちょっと解説

FBD TechFBD Tech

パスワード認証もしたい場合は?

もちろんできます。
メール認証のユーザーにパスワードでもログインするようにします。
上の方法でユーザーを作ったら、以下を使ってパスワードありのユーザーにしましょう。

パスワード設定

await currentUser.updatePassword(password);
await currentUser.reauthenticateWithCredential(
EmailAuthProvider.credential(
    email: currentUser!.email!, password: password),
);

パスワードが登録されているユーザーかをチェック

final signInMethods = await FirebaseAuth.instance.fetchSignInMethodsForEmail(currentUser!.email!);
return signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD);