📑

Auto RouteでFirebaseAuthを使う

2023/11/20に公開

またやってみたけど

前回中と半端な方法で、auto_routeの認証機能を実装してみた。しかし、なんだか満足できなくて、またやってみた。この方法も良いものか???
https://zenn.dev/joo_hashi/articles/187136f6475d9d

とりあえずやってみる

前回と同じパッケージを追加して、コードを書いてアプリをビルドします。

📄ページを作成

ログイン後のページを作成します。ログアウトボタンを押すと、ログアウトした後に、画面遷移のコードが実行されます。

ログイン後のページ
import 'package:auto_router/route/router.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';

()
class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () async {
                await FirebaseAuth.instance.signOut();
                // ログアウトしたら、ログインページへリダイレクト
                if (context.mounted) {
                  context.router.replace(LoginRoute(onResult: (success) {
                    return;
                  }));
                }
              },
              child: const Text('ログインページへ'),
            ),
          ],
        ),
      ),
    );
  }
}

ログインページを作成します。ルートの定義でこのページを最初に表示する設定にします。

ログインページ
import 'package:auto_router/route/router.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';

()
class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  
  void initState() {
    checkAuthState();
    super.initState();
  }

  // ログイン状態をauthStateChangesで、listenして確認
  void checkAuthState() {
    FirebaseAuth.instance.authStateChanges().listen((User? user) {
      if (user != null) {
        context.router.replace(const HomeRoute());
      }
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                FirebaseAuth.instance.signInAnonymously();
              },
              child: const Text('登録しないで利用'),
            ),
          ],
        ),
      ),
    );
  }
}

ルートの定義は、router.dartで行います。ルートを定義したら、ファイルを自動生成するコマンドを実行してください。

flutter pub run build_runner watch --delete-conflicting-outputs
ルートの定義ファイル
import 'package:auto_route/auto_route.dart';
import 'package:auto_router/page/home_page.dart';
import 'package:auto_router/page/login_page.dart';
import 'package:firebase_auth/firebase_auth.dart';

part 'router.gr.dart';

class AuthGuard extends AutoRouteGuard {
 
 void onNavigation(NavigationResolver resolver, StackRouter router) {
      // FirebaseAuthのログイン状態を確認
      final isAuth = FirebaseAuth.instance.currentUser != null;
      // ログイン状態なら、trueを返す
      if(isAuth){
        resolver.next(true);
      }else{
      // ログイン状態でなければ、ログインページへリダイレクト
         resolver.redirect(LoginRoute(onResult: (success){

               resolver.next(success);
          }));
         }
     }
}

()
class AppRouter extends _$AppRouter {

 
 List<AutoRoute> get routes => [
    AutoRoute(page: LoginRoute.page, initial: true),
    AutoRoute(page: HomeRoute.page, guards: [AuthGuard()]),
  ];
}

auto_routeをFlutterで使用できるように、MaterialAppの設定を行います。

アプリを実行するファイル
import 'package:auto_router/firebase_options.dart';
import 'package:auto_router/route/router.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    // AppRouterクラスをインスタンス化
    AppRouter appRouter = AppRouter();
    return MaterialApp.router(
      // MaterialApp.routerを使用
      routerConfig: appRouter.config(),
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
    );
  }
}

画面遷移のスクリーンショット

アプリをビルドした時は、認証が通っているかチェックします。

これが、ログインページでボタンを押すと、匿名認証で、HomePageへ行きますが、認証が通っていなかったら、AuthGuardを使って、HomePageへの画面遷移を防ぐことができます。

ログインできると、このページが表示されます。

ログアウトすると、Login Pageへ遷移します。Login Pageへ戻ってくると認証が通っているかチエックが行われます。

最後に

やってみて、感じたことは認証状態でログイン後のページへリダイレクトするのと、ログアウトするときに、画面遷移のコードを書く必要がありました。

go routerだと、リダイレクトの機能を実装すると、アプリをビルドしたときに、authStateChangesで監視されている状態と組み合わせて、表示するページを切り替えることができます。
しかし、auto routeだと、画面遷移のコードを書く必要がありました。

まだまだ、違和感のあるコードしか書けません???
またやってみたいと思ったのは、サイバーエージェントの勉強会に参加したことがきっかけでした。

イベント情報はこちら
https://cyberagent.connpass.com/event/298289/

Discussion