Flutterアプリケーション開発概論

【認証分岐】AuthGateでログイン済み・未ログインの画面を切り替える

11LINE風チームタスク管理アプリを作りながら、ログイン・データベース・権限管理を学ぶ
FlutteriOSAndroidMacOSWindows基礎から学ぶ開発アプリ開発

このページでやること

このページでは、ログインしている人と、まだログインしていない人で、表示する画面を切り替えます。

今回作るのは、AuthGate という部品です。

AuthGate とは、ログイン状態を見て、表示する画面を振り分ける入口のようなWidgetです。

ログインしていない
↓
LoginPageを表示

ログインしている
↓
TeamListPageを表示

この仕組みを作ると、アプリを開いたときに、毎回ログイン画面を出す必要がなくなります。


今日のゴール

MaterialApphome に、次のように書ける状態にします。

home: const AuthGate(),

そして、AuthGate の中でログイン状態を確認します。

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const LoadingPage(message: 'ログイン状態を確認しています...');
        }

        final user = snapshot.data;

        if (user == null) {
          return const LoginPage();
        }

        return const TeamListPage();
      },
    );
  }
}

まず出てくる単語

単語一言説明
認証ユーザーが誰かを確認すること
ログイン状態今、ユーザーがログインしているかどうか
AuthGateログイン済みかどうかで画面を切り替える入口
StreamBuilder変化するデータを監視して画面を更新するWidget
UserFirebase Authenticationのログインユーザー情報
snapshotStreamBuilderが受け取った最新データ
nullデータがない状態
LoadingPage読み込み中に表示する画面
LoginPageログインしていない人に表示する画面
TeamListPageログイン済みの人に表示する画面

Widget とは、Flutterの画面部品のことです。


このページではnpmや環境変数は使いません

このページで使うのは、FlutterとFirebase Authenticationです。

npmは使いません。

npmとは、Node.jsのパッケージを管理する道具です。

環境変数も設定しません。

環境変数とは、パソコン全体で使う設定値のことです。

このページでやることはこれだけです。

main.dartを開く
↓
AuthGateを書く
↓
MaterialAppのhomeに設定する
↓
保存する
↓
flutter runで確認する

Step 1:main.dartを開く

Flutterプロジェクトの中で、次のファイルを開きます。

lib/main.dart

VS Codeを使っている場合は、ターミナルで次を実行してもOKです。

code lib/main.dart

code が使えない場合は、VS Codeの左側から lib/main.dart を開いてください。


Step 2:firebase_authのimportを確認する

main.dart の上の方に、次の1行があるか確認します。

import 'package:firebase_auth/firebase_auth.dart';

これは、Firebase AuthenticationをFlutterから使うための読み込みです。

import とは、別の機能をこのファイルで使えるようにすることです。

この1行がないと、FirebaseAuthUser が使えません。


Step 3:MaterialAppのhomeを確認する

WorkBoardApp の中にある MaterialApp を探します。

次のようになっているか確認してください。

return MaterialApp(
  title: 'WorkBoard Firebase',
  debugShowCheckedModeBanner: false,
  theme: ThemeData(
    // テーマ設定
  ),
  home: const AuthGate(),
);

大事なのは、この行です。

home: const AuthGate(),

home とは、アプリを起動したときに最初に表示する画面です。

つまり、このアプリでは、最初に AuthGate を表示します。


Step 4:AuthGateを追加する

AppColors の下あたりに、次のコードを追加します。

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const LoadingPage(message: 'ログイン状態を確認しています...');
        }

        final user = snapshot.data;

        if (user == null) {
          return const LoginPage();
        }

        return const TeamListPage();
      },
    );
  }
}

このコードで、ログイン状態を見て画面を切り替えます。

ログイン状態を確認中
↓
LoadingPage

ログインしていない
↓
LoginPage

ログインしている
↓
TeamListPage

Step 5:AuthGateの中身を短く理解する

まず、この部分です。

stream: FirebaseAuth.instance.authStateChanges(),

authStateChanges() は、ログイン状態の変化を監視する機能です。

監視とは、変化があったら気づけるように見ておくことです。

たとえば、

ログインした
ログアウトした
アプリを開いたらすでにログイン済みだった

という変化を見てくれます。


Step 6:StreamBuilderとは何か

この部分を見ます。

return StreamBuilder<User?>(
  stream: FirebaseAuth.instance.authStateChanges(),
  builder: (context, snapshot) {
    // 画面を返す
  },
);

StreamBuilder は、変化するデータに合わせて画面を作り直すWidgetです。

今回は、ログイン状態が変わるたびに画面を切り替えます。

ログイン状態が変わる
↓
StreamBuilderが気づく
↓
画面を作り直す

User?? は、「Userかもしれないし、nullかもしれない」という意味です。

ログインしていれば User が入ります。

ログインしていなければ null になります。


Step 7:読み込み中の画面

この部分です。

if (snapshot.connectionState == ConnectionState.waiting) {
  return const LoadingPage(message: 'ログイン状態を確認しています...');
}

ConnectionState.waiting は、まだログイン状態を確認中という意味です。

確認中に真っ白な画面になると不安なので、読み込み画面を出します。

ログイン状態を確認しています...

このような表示が出れば、ユーザーにとっても安心です。


Step 8:ログインしていない場合

この部分です。

final user = snapshot.data;

if (user == null) {
  return const LoginPage();
}

snapshot.data には、ログイン中のユーザー情報が入ります。

ログインしていない場合は、null になります。

null とは、データがない状態のことです。

つまり、ここではこう判断しています。

userがない
↓
ログインしていない
↓
LoginPageを表示

Step 9:ログインしている場合

最後の部分です。

return const TeamListPage();

ここまで来たということは、usernull ではありません。

つまり、ログイン済みです。

だから、チーム一覧画面を表示します。

userがある
↓
ログイン済み
↓
TeamListPageを表示

Step 10:LoadingPageを用意する

AuthGate の中で LoadingPage を使っています。

まだ作っていない場合は、次のコードを追加します。

class LoadingPage extends StatelessWidget {
  const LoadingPage({
    super.key,
    required this.message,
  });

  final String message;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: AppColors.bg,
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const CircularProgressIndicator(),
            const SizedBox(height: 16),
            Text(
              message,
              style: const TextStyle(
                color: AppColors.subText,
                fontWeight: FontWeight.w600,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

CircularProgressIndicator は、ぐるぐる回る読み込み表示です。

Scaffold は、Flutterの基本画面の土台です。


Step 11:まだLoginPageやTeamListPageがない場合

このページだけを先に試すと、次のエラーが出ることがあります。

The name 'LoginPage' isn't a class.

これは、LoginPage をまだ作っていないという意味です。

同じように、TeamListPage がまだない場合もエラーになります。

一時的に確認したい場合は、仮の画面を作ってください。

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('ログイン画面'),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('チーム一覧画面'),
      ),
    );
  }
}

完成コードを使っている場合は、すでに LoginPageTeamListPage があるので、この仮コードは不要です。


Step 12:保存する

main.dart を保存します。

Macの場合:

command + S

Windowsの場合:

Ctrl + S

Step 13:実行する

ターミナルで実行します。

flutter run

すでにアプリが起動している場合は、ターミナルで r を押します。

r

r はホットリロードです。

ホットリロードとは、アプリを起動したまま変更を反映する機能です。


Step 14:画面を確認する

まだログインしていない場合は、ログイン画面が表示されます。

WorkBoard
メールアドレス
パスワード
ログイン

すでにログインしている場合は、チーム一覧画面が表示されます。

トーク
まだチームがありません

ログアウトすると、またログイン画面に戻ります。

ログアウト
↓
AuthGateがログイン状態の変化に気づく
↓
LoginPageに切り替わる

画面の切り替わりイメージ

AuthGate は、アプリの入口に立っている受付のようなものです。

アプリ起動
↓
AuthGate
↓
ログイン済み?
↓
はい → TeamListPage
↓
いいえ → LoginPage

この仕組みがあると、画面遷移を自分で細かく書かなくても、ログイン状態に合わせて自然に画面が変わります。


1か所だけ変更してみる

読み込み中の文字を変えてみます。

この行を探します。

return const LoadingPage(message: 'ログイン状態を確認しています...');

次のように変えます。

return const LoadingPage(message: '少しだけお待ちください...');

保存して、ホットリロードします。

r

アプリ起動時の読み込み文字が変わればOKです。

確認したら、元に戻しておきます。

return const LoadingPage(message: 'ログイン状態を確認しています...');

よくあるエラーと直し方

エラー原因直し方
FirebaseAuth isn't definedimportがないimport 'package:firebase_auth/firebase_auth.dart'; を追加
User isn't a typefirebase_authのimportがないfirebase_auth.dart を確認
LoginPage isn't a classLoginPageがまだないLoginPageを作る
TeamListPage isn't a classTeamListPageがまだないTeamListPageを作る
ずっと読み込み中Firebase初期化がうまくいっていないFirebase.initializeApp() を確認
ログイン後に切り替わらないauthStateChangesを使っていないFirebaseAuth.instance.authStateChanges() を確認

FirebaseAuth isn't defined** が出たとき**

このエラーが出たら、main.dart の上に次の1行を追加します。

import 'package:firebase_auth/firebase_auth.dart';

保存します。

command + S

もう一度実行します。

flutter run

LoginPage** がないと言われたとき**

このページだけを先に進めている場合は、仮の LoginPage を作ってください。

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('ログイン画面'),
      ),
    );
  }
}

あとで本物のログイン画面に差し替えます。


TeamListPage** がないと言われたとき**

仮の TeamListPage を作ってください。

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('チーム一覧画面'),
      ),
    );
  }
}

あとで本物のトーク一覧画面に差し替えます。


最短作業まとめ

読むのが大変な人は、ここだけ見てください。

1. firebase_auth をimportする

import 'package:firebase_auth/firebase_auth.dart';

2. MaterialApp のhomeをAuthGateにする

home: const AuthGate(),

3. AuthGateを追加する

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const LoadingPage(message: 'ログイン状態を確認しています...');
        }

        final user = snapshot.data;

        if (user == null) {
          return const LoginPage();
        }

        return const TeamListPage();
      },
    );
  }
}

4. 保存する

command + S

5. 実行する

flutter run

チェックリスト

□ main.dartを開いた
□ firebase_authをimportした
□ MaterialAppのhomeをAuthGateにした
□ AuthGateを追加した
□ LoadingPageがある
□ LoginPageがある
□ TeamListPageがある
□ 保存した
□ flutter runで起動した
□ 未ログインならLoginPageが出る
□ ログイン済みならTeamListPageが出る

ミニ確認問題

Q1. AuthGateは何をするWidgetですか?

回答

ログイン済みか未ログインかを確認して、表示する画面を切り替えるWidgetです。


Q2. authStateChanges() は何を確認しますか?

回答

Firebase Authenticationのログイン状態の変化を確認します。

ログインしたとき、ログアウトしたとき、アプリ起動時のログイン状態を見ます。


Q3. user == null は何を意味しますか?

回答

ログインしているユーザーがいないという意味です。

そのため、ログイン画面を表示します。


Q4. このページでnpmや環境変数は必要ですか?

回答

必要ありません。

このページでは、main.dartAuthGate を作り、ログイン状態で画面を切り替えるだけです。


このページのまとめ

  • AuthGate は、ログイン済み・未ログインを分ける入口。
  • FirebaseAuth.instance.authStateChanges() でログイン状態を監視する。
  • StreamBuilder は、変化するデータに合わせて画面を更新するWidget。
  • user == null なら未ログインなので LoginPage を表示する。
  • user があるならログイン済みなので TeamListPage を表示する。
  • MaterialApphomeAuthGate を設定する。
  • このページではnpmや環境変数は不要。
  • 保存して実行し、画面が切り替わるか確認する。

次のページでやること

次のページでは、ログイン画面を作ります。

メールアドレスとパスワードを入力して、Firebase AuthenticationにログインするUIを作っていきます。

教材トップへ戻る