22
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Flutter と Firebase Auth を用いたアプリで、起動時にログイン状態に応じたページを表示する方法

Flutter と Firebase を使用したアプリを開発する際に、Firebase Auth を使用することは多いと考えられますが、本記事では、アプリの起動時に Firebase Auth のログイン状態に応じたページを返す方法についてまとめます。

達成したい状況は、

  • アプリの起動時(使用中)にユーザーの Firebase Auth のログイン状態を確認・監視する
  • そのログイン状態に応じて、未ログイン時のサイン画面、ログイン済み時のホーム画面などを出し分ける

ということです。

そのような方法を学ぶ前には、次のようなコードを実装しているかもしれません。

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Flutter app',
        home: SignInPage(),
}

class SignInPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => const Scaffold(
        body: Center(
          child: Text('未サインイン時に表示するサインイン画面です。'),
        ),
      );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => const Scaffold(
        body: Center(
          child: Text('サインイン済み時に表示するホーム画面です。'),
        ),
      );
}

このようにすると、ユーザーのサインイン状態にかかわらず、毎回 MaterialApphome 属性に指定された SignInPage が表示されることになってしまいます。

これを解決し、冒頭の達成したい状況を満たすための最も簡単な方法の一つは、 FirebaseAuth.instanceauthStateChanges() メソッドと StreamBuilder を使用することです。

公式の Flutter Fire のドキュメント にも記述があります。

Firebase Auth enables you to subscribe in realtime to this state via a Stream. Once called, the stream provides an immediate event of the user's current authentication state, and then provides subsequent events whenever the authentication state changes. To subscribe to these changes, call the authStateChanges() method on your FirebaseAuth instance:

と説明されている通り、authStateChanges() メソッドによって、FirebaseAuth インスタンスのログイン状態の変更を監視 (subscribe) することができ、それを Stream 型でリアルタイムに受け取ることができます。

つまり、次のようなソースコードを記述すれば完成です。

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Flutter app',
        home: StreamBuilder<User?>(
          stream: FirebaseAuth.instance.authStateChanges(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              // スプラッシュ画面などに書き換えても良い
              return const SizedBox();
            }
            if (snapshot.hasData) {
              // User が null でなない、つまりサインイン済みのホーム画面へ
              return HomePage();
            }
            // User が null である、つまり未サインインのサインイン画面へ
            return SignInPage();
          },
        ),
      );
}

class SignInPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => const Scaffold(
        body: Center(
          child: Text('未サインイン時に表示するサインイン画面です。'),
        ),
      );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => const Scaffold(
        body: Center(
          child: Text('サインイン済み時に表示するホーム画面です。'),
        ),
      );
}

StreamBuilderstream 属性には、Firebase Auth の authStateChanges() メソッドを指定しており、 Stream で Firebase Auth の User? 型を返します。つまり、サインイン済みであることが確認されればそのユーザーを、そうでなければ null を返すということです。

AsyncSnapshot<User?> 型の snapshotconnectionStatesnapshot.data の内容に応じてホーム画面とサインイン画面を出し分ければ、目的通りの実装が完成します。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
22
Help us understand the problem. What are the problem?