1. 始める前に
この Codelab では、FlutterFire UI パッケージを使用して Flutter アプリに Firebase Authentication を追加する方法を学びます。このパッケージを使用すると、メールとパスワード認証と Google ログイン認証の両方を Flutter アプリに追加できます。また、Firebase プロジェクトを設定する方法や、FlutterFire CLI を使用して Flutter アプリで Firebase を初期化する方法も学習します。
前提条件
この Codelab は、Flutter の使用経験があることを前提としています。まだの場合は、まず基本的な使い方を学習してください。次のリンクが役に立ちます。
Firebase の経験も必要ですが、Flutter プロジェクトに Firebase を追加したことがなくても問題ありません。Firebase コンソールについてよく知らない場合や、Firebase をまったく初めて使用する場合は、まず次のリンクをご覧ください。
作成するアプリの概要
この Codelab では、Firebase を認証に使用して、Flutter アプリの認証フローを構築する手順を説明します。このアプリには、ログイン画面、[登録] 画面、パスワード再設定画面、ユーザー プロフィール画面があります。
学習内容
この Codelab では、次のことを学びます。
- Flutter アプリに Firebase を追加する
- Firebase コンソールの設定
- Firebase CLI を使用して Firebase をアプリケーションに追加する
- FlutterFire CLI を使用して Dart で Firebase 構成を生成する
- Flutter アプリに Firebase Authentication を追加する
- コンソールでの Firebase Authentication の設定
firebase_ui_auth
パッケージを使用してメールとパスワードによるログインを追加するfirebase_ui_auth
パッケージを使用したユーザー登録の追加- 「パスワードをお忘れですか?」ページを追加する
firebase_ui_auth
を使用して Google ログインを追加する- 複数のログイン プロバイダで動作するようにアプリを構成する。
firebase_ui_auth
パッケージを使用してアプリケーションにユーザー プロフィール画面を追加する
この Codelab では、firebase_ui_auth
パッケージを使用して堅牢な認証システムを追加することに特に重点を置いています。ご覧のとおり、上記のすべての機能を備えたこのアプリ全体を、約 100 行のコードで実装できます。
必要なもの
- Flutter の実務知識があり、SDK がインストールされている
- テキスト エディタ(JetBrains IDE、Android Studio、VS Code は Flutter でサポートされています)
- Google Chrome ブラウザ、または Flutter のその他の優先開発ターゲット。(この Codelab の一部のターミナル コマンドは、Chrome でアプリを実行することを前提としています)。
2. Firebase プロジェクトを作成して設定する
最初に完了する必要があるタスクは、Firebase ウェブ コンソールで Firebase プロジェクトを作成することです。
Firebase プロジェクトを作成する
- Google アカウントを使用して Firebase コンソールにログインします。
- ボタンをクリックして新しいプロジェクトを作成し、プロジェクト名(例:
FlutterFire-UI-Codelab
)を入力します。
- [続行] をクリックします。
- Firebase の利用規約が表示されたら、内容を読み、同意して [続行] をクリックします。
- (省略可)Firebase コンソールで AI アシスタンス(「Gemini in Firebase」)を有効にします。
- この Codelab では Google アナリティクスは必要ないため、Google アナリティクスのオプションをオフに切り替えます。
- [プロジェクトを作成] をクリックし、プロジェクトのプロビジョニングが完了するまで待ってから、[続行] をクリックします。
Firebase プロジェクトの詳細については、Firebase プロジェクトについて理解するをご覧ください。
Firebase Authentication 用にメールログインを有効にする
作成するアプリは、Firebase Authentication を使用して、ユーザーがアプリにログインできるようにします。また、新しいユーザーが Flutter アプリケーションから登録することもできます。
Firebase Authentication は、Firebase コンソールを使用して有効にする必要があります。また、有効にしたら特別な設定を行う必要があります。
ユーザーがウェブアプリにログインできるようにするには、まずメール/パスワードのログイン方法を使用します。後で、Google ログイン メソッドを追加します。
- Firebase コンソールの左側のパネルで、[ビルド] メニューを開きます。
- [認証] をクリックし、[開始] ボタンをクリックしてから、[ログイン方法] タブをクリックします(または、[ログイン方法] タブに直接移動します)。
- [ログイン プロバイダ] リストで [メール/パスワード] をクリックし、[有効にする] スイッチをオンの位置に設定して、[保存] をクリックします。
3. Flutter アプリを設定する
始める前に、スターター コードをダウンロードして Firebase CLI をインストールする必要があります。
スターター コードを取得する
コマンドラインから GitHub リポジトリのクローンを作成します。
git clone https://github.com/flutter/codelabs.git flutter-codelabs
または、GitHub の CLI ツールがインストールされている場合は、次の操作を行います。
gh repo clone flutter/codelabs flutter-codelabs
サンプルコードのクローンは、マシン上の flutter-codelabs
ディレクトリに作成する必要があります。このディレクトリには、一連の Codelab のコードが含まれています。この Codelab のコードは、サブディレクトリ flutter-codelabs/firebase-auth-flutterfire-ui
にあります。
ディレクトリ flutter-codelabs/firebase-auth-flutterfire-ui
には 2 つの Flutter プロジェクトが含まれています。1 つは complete
、もう 1 つは start
と呼ばれます。start
ディレクトリには未完成のプロジェクトが含まれており、このディレクトリで最も多くの時間を費やすことになります。
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
先に進みたい場合や、完成した状態を確認したい場合は、complete という名前のディレクトリで相互参照してください。
Codelab に沿って自分でコードを追加する場合は、flutter-codelabs/firebase-auth-flutterfire-ui/start
の Flutter アプリから始め、Codelab 全体を通してそのプロジェクトにコードを追加する必要があります。そのディレクトリを開くか、お好みの IDE にインポートします。
Firebase CLI のインストール
Firebase CLI は、Firebase プロジェクトを管理するためのツールを提供します。CLI は FlutterFire CLI に必要です。FlutterFire CLI は後でインストールします。
CLI のインストール方法はいくつかあります。オペレーティング システムで利用可能なすべてのオプションについては、firebase.google.com/docs/cli をご覧ください。
CLI をインストールしたら、Firebase で認証する必要があります。
- Google アカウントで Firebase にログインするには、次のコマンドを実行します。
firebase login
- このコマンドにより、ローカルマシンが Firebase に接続され、Firebase プロジェクトへのアクセスが許可されます。
- Firebase プロジェクトを一覧表示し、CLI が正しくインストールされていて、アカウントにアクセスできることをテストします。次のコマンドを実行します。
firebase projects:list
- Firebase コンソールと同じ Firebase プロジェクトが表示されているはずです。
flutterfire-ui-codelab.
以上が表示されます。
FlutterFire CLI をインストールする
FlutterFire CLI は、Flutter アプリでサポートされているすべてのプラットフォームで Firebase のインストール プロセスを簡素化するツールです。Firebase CLI をベースに構築されています。
まず、CLI をインストールします。
dart pub global activate flutterfire_cli
CLI がインストールされていることを確認します。次のコマンドを実行し、CLI がヘルプ メニューを出力することを確認します。
flutterfire --help
Firebase プロジェクトを Flutter アプリに追加する
FlutterFire を構成する
FlutterFire を使用すると、Flutter アプリで Firebase を使用するために必要な Dart コードを生成できます。
flutterfire configure
このコマンドを実行すると、使用する Firebase プロジェクトと設定するプラットフォームを選択するように求められます。
次のスクリーンショットは、回答する必要があるプロンプトを示しています。
- 使用するプロジェクトを選択します。この場合は、
flutterfire-ui-codelab
を使用します。
- 使用するプラットフォームを選択します。この Codelab では、ウェブ、iOS、Android 向けに Flutter 用 Firebase Authentication を構成する手順を説明しますが、すべてのオプションを使用するように Firebase プロジェクトを設定することもできます。
- このスクリーンショットは、プロセスの最後に表示される出力を示しています。Firebase に慣れている方は、コンソールでプラットフォーム アプリケーション(Android アプリケーションなど)を作成する必要がなく、FlutterFire CLI が自動的に作成したことに気づくでしょう。
完了したら、テキスト エディタで Flutter アプリを確認します。FlutterFire CLI が firebase_options.dart
というファイルを変更しました。このファイルには、各プラットフォームに必要な Firebase 構成を保持する静的変数を持つ FirebaseOptions
というクラスが含まれています。flutterfire configure
の実行時にすべてのプラットフォームを選択した場合は、web
、android
、ios
、macos
という名前の静的値が表示されます。
lib/firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
measurementId: 'G-DGF0CP099H',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
Firebase では、Firebase プロジェクト内の特定のプラットフォームの特定のビルドを指すために「アプリケーション」という単語を使用します。たとえば、FlutterFire-ui-codelab という Firebase プロジェクトには、Android 用、iOS 用、macOS 用、ウェブ用の複数のアプリケーションがあります。
DefaultFirebaseOptions.currentPlatform
メソッドは、Flutter によって公開された TargetPlatform
列挙型を使用して、アプリが実行されているプラットフォームを検出し、正しい Firebase アプリケーションに必要な Firebase 構成値を返します。
Flutter アプリに Firebase パッケージを追加する
設定の最後の手順は、関連する Firebase パッケージを Flutter プロジェクトに追加することです。firebase_options.dart
ファイルには、まだ追加されていない Firebase パッケージに依存しているため、エラーが表示されます。ターミナルで、Flutter プロジェクトのルート(flutter-codelabs/firebase-emulator-suite/start
)に移動します。次に、次の 3 つのコマンドを実行します。
flutter pub add firebase_core firebase_auth firebase_ui_auth
この時点で必要なパッケージはこれだけです。
Firebase を初期化する
追加したパッケージと DefaultFirebaseOptions.currentPlatform,
を使用するには、main.dart
ファイルの main
関数のコードを更新します。
lib/main.dart
import 'package:firebase_core/firebase_core.dart'; // Add this import
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart'; // And this import
// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';
void main() async {
// Add from here...
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
// To here.
runApp(const MyApp(clientId: clientId));
}
このコードは次の 2 つの処理を行います。
WidgetsFlutterBinding.ensureInitialized()
は、Flutter フレームワークが完全に起動するまで、Flutter にアプリケーション ウィジェット コードの実行を開始しないように指示します。Firebase はネイティブ プラットフォーム チャネルを使用するため、フレームワークが実行されている必要があります。Firebase.initializeApp
は、Flutter アプリと Firebase プロジェクト間の接続を設定します。DefaultFirebaseOptions.currentPlatform
は、生成されたfirebase_options.dart
ファイルからインポートされます。この静的な値は、実行中のプラットフォームを検出し、対応する Firebase キーを渡します。
4. Firebase UI Auth の初期ページを追加
Firebase UI for Auth には、アプリケーションの画面全体を表すウィジェットが用意されています。これらの画面は、ログイン、登録、パスワードを忘れた場合、ユーザー プロフィールなど、アプリケーション全体でさまざまな認証フローを処理します。まず、メイン アプリケーションの認証ガードとして機能するランディング ページをアプリに追加します。
Material アプリまたは Cupertino アプリ
FlutterFire UI では、アプリケーションが MaterialApp
または CupertinoApp
のいずれかでラップされている必要があります。選択内容に応じて、UI には Material ウィジェットと Cupertino ウィジェットの違いが自動的に反映されます。この Codelab では、app.dart
でアプリにすでに追加されている MaterialApp
を使用します。
lib/app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: AuthGate(clientId: clientId),
);
}
}
認証状態を確認する
ログイン画面を表示する前に、ユーザーが認証されているかどうかを判断する必要があります。この確認を行う最も一般的な方法は、Firebase Auth プラグインを使用して FirebaseAuth
の authStateChanges
をリッスンすることです。
上記のコードサンプルでは、MaterialApp
は build
メソッドで AuthGate
ウィジェットをビルドしています。(これは FlutterFire UI で提供されるものではなく、カスタム ウィジェットです)。
そのウィジェットは、authStateChanges
ストリームを含めるように更新する必要があります。
authStateChanges
API は、現在のユーザー(ログインしている場合)または null(ログインしていない場合)のいずれかを含む Stream
を返します。アプリケーションでこの状態をサブスクライブするには、Flutter の StreamBuilder ウィジェットを使用して、ストリームを渡します。
StreamBuilder
は、渡された Stream からのデータの最新のスナップショットに基づいて自身をビルドするウィジェットです。Stream
が新しいスナップショットを出力すると、自動的に再構築されます。
auth_gate.dart
のコードを更新します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider; // Add this import
import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // And this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>( // Modify from here...
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: []);
}
return const HomeScreen();
},
); // To here.
}
}
StreamBuilder.stream
には、前述のストリームであるFirebaseAuth.instance.authStateChanged
が渡されます。ユーザーが認証済みの場合、Firebase のUser
オブジェクトが返されます。それ以外の場合はnull
が返されます。- 次に、コードは
snapshot.hasData
を使用して、ストリームの値にUser
オブジェクトが含まれているかどうかを確認します。 - ない場合は、
SignInScreen
ウィジェットが返されます。この画面はまだ何も行いません。次のステップで更新します。 - それ以外の場合は、認証されたユーザーのみがアクセスできるアプリケーションのメイン部分である
HomeScreen
を返します。
SignInScreen
は、FlutterFire UI パッケージから提供されるウィジェットです。これは、この Codelab の次のステップで扱います。この時点でアプリを実行すると、空白のログイン画面が表示されます。
5. ログイン画面
FlutterFire UI が提供する SignInScreen
ウィジェットは、次の機能を追加します。
- ユーザーがログインできるようにする
- パスワードを忘れた場合は、[パスワードをお忘れですか?] をタップすると、パスワードを再設定するためのフォームが表示されます。
- ユーザーがまだ登録していない場合は、[登録] をタップすると、登録できる別のフォームに移動します。
この場合も、必要なコードは数行のみです。AuthGate
ウィジェットのコードを思い出してください。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: [EmailAuthProvider()]); // Modify this line
}
return const HomeScreen();
},
);
}
}
SignInScreen
ウィジェットとその providers
引数は、前述のすべての機能を取得するために必要な唯一のコードです。「メールアドレス」と「パスワード」のテキスト入力と「ログイン」ボタンがあるログイン画面が表示されます。
機能的には問題ありませんが、スタイルが適用されていません。ウィジェットは、ログイン画面の見た目をカスタマイズするためのパラメータを公開します。たとえば、会社のロゴを追加できます。
ログイン画面をカスタマイズする
headerBuilder
SignInScreen.headerBuilder
引数を使用すると、ログイン フォームの上に任意のウィジェットを追加できます。このウィジェットは、モバイル デバイスなどの狭い画面にのみ表示されます。ワイド画面では、この Codelab で後ほど説明する SignInScreen.sideBuilder
を使用できます。
次のコードで lib/auth_gate.dart
ファイルを更新します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen( // Modify from here...
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
); // To here.
}
return const HomeScreen();
},
);
}
}```
The headerBuilder argument requires a function of the type HeaderBuilder, which
is defined in the FlutterFire UI package.
```dart
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
コールバックであるため、BuildContext
や BoxConstraints
などの使用可能な値を公開し、ウィジェットを返す必要があります。返されたウィジェットは画面の上部に表示されます。この例では、新しいコードによって画面の上部に画像が追加されます。アプリケーションは次のようになります。
Subtitle Builder
ログイン画面には、画面をカスタマイズできる 3 つの追加パラメータ(subtitleBuilder
、footerBuilder
、sideBuilder
)が用意されています。
subtitleBuilder
は、コールバック引数に AuthAction
タイプの action が含まれている点が若干異なります。AuthAction
は、ユーザーが現在いる画面が「ログイン」画面か「登録」画面かを検出するために使用できる列挙型です。
auth_gate.dart のコードを更新して、subtitleBuilder
を使用します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) { // Add from here...
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
フッター ビルダー
footerBuilder 引数は subtitleBuilder と同じです。画像ではなくテキストを対象としているため、BoxConstraints
や shrinkOffset
は公開されません。もちろん、任意のウィジェットを追加することもできます。
次のコードを使用して、ログイン画面にフッターを追加します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) { // Add from here...
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
Side Builder
SignInScreen.sidebuilder 引数はコールバックを受け取ります。今回は、そのコールバックの引数は BuildContext
と double shrinkOffset
です。sideBuilder
が返すウィジェットは、ログイン フォームの左側に表示され、ワイド画面でのみ表示されます。つまり、ウィジェットはパソコンとウェブアプリでのみ表示されます。
内部的には、FlutterFire UI はブレークポイントを使用して、ヘッダー コンテンツを表示するか(モバイルなどの縦長の画面)、サイド コンテンツを表示するか(パソコンやウェブなどの横長の画面)を判断します。具体的には、画面の幅が 800 ピクセルを超える場合は、サイドビルダーのコンテンツが表示され、ヘッダーのコンテンツは表示されません。画面の幅が 800 ピクセル未満の場合は、逆になります。
auth_gate.dart のコードを更新して、sideBuilder
ウィジェットを追加します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
ウィンドウの幅を広げると、アプリは次のようになります(Flutter ウェブまたは MacOS を使用している場合)。
ユーザーを作成する
これで、この画面のコードはすべて完成しました。ただし、ログインする前にユーザーを作成する必要があります。登録画面で行うことも、Firebase コンソールでユーザーを作成することもできます。
コンソールを使用するには:
- Firebase コンソールの [ユーザー] テーブルに移動します。[flutterfire-ui-codelab] を選択します。別の名前を使用した場合は、別のプロジェクトを選択します。次の表が表示されます。
- [ユーザーを追加] ボタンをクリックします。
- 新しいユーザーのメールアドレスとパスワードを入力します。下の画像のように、偽のメールアドレスとパスワードを入力してもかまいません。この方法でもアカウントを作成できますが、偽のメールアドレスを使用すると [パスワードをお忘れの場合] 機能が動作しません。
- [ユーザーを追加]
をクリックします。
これで、Flutter アプリケーションに戻り、ログインページを使用してユーザーをログインさせることができます。アプリの表示は次のようになります。
6. プロフィール画面
FlutterFire UI には ProfileScreen
ウィジェットも用意されています。このウィジェットを使用すると、数行のコードで多くの機能を利用できます。
ProfileScreen
ウィジェットを追加
テキスト エディタで home.dart
ファイルに移動します。次のコードで更新します。
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => const ProfileScreen(),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
新しいコードの注目点は、IconButton.isPressed
メソッドに渡されるコールバックです。この IconButton
が押されると、アプリケーションは新しい匿名ルートを作成して、そのルートに移動します。このルートには、MaterialPageRoute.builder
コールバックから返された ProfileScreen
ウィジェットが表示されます。
アプリを再読み込みし、右上(アプリバー内)のアイコンを押すと、次のようなページが表示されます。
これは、FlutterFire UI ページで提供される標準の UI です。すべてのボタンとテキスト フィールドが Firebase Auth に接続されており、すぐに使用できます。たとえば、[名前] テキスト フィールドに名前を入力すると、FlutterFire UI が FirebaseAuth.instance.currentUser?.updateDisplayName
メソッドを呼び出し、その名前が Firebase に保存されます。
ログアウト
現時点では、[ログアウト] ボタンを押してもアプリは変更されません。ログアウトはされますが、AuthGate ウィジェットに戻ることはありません。これを実装するには、ProfileScreen.actions パラメータを使用します。
まず、home.dart のコードを更新します。
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
これで、ProfileScreen
のインスタンスを作成するときに、アクションのリストを ProfileScreen.actions
引数に渡すようになります。これらのアクションは FlutterFireUiAction
型です。FlutterFireUiAction
のサブタイプであるクラスは多数存在します。一般に、これらのクラスは、さまざまな認証状態の変化に対応するようアプリに指示するために使用します。SignedOutAction は、Firebase 認証状態が currentUser が null に変わったときに、指定したコールバック関数を呼び出します。
SignedOutAction
がトリガーされたときに Navigator.of(context).pop()
を呼び出すコールバックを追加することで、アプリは前のページに移動します。このサンプルアプリには永続的なルートが 1 つだけあります。ログインしているユーザーがいない場合はログイン画面が表示され、ログインしているユーザーがいる場合はホームページが表示されます。ユーザーがログアウトするとこの処理が発生するため、アプリにログイン画面が表示されます。
プロフィール ページをカスタマイズする
ログイン画面と同様に、プロフィール ページもカスタマイズできます。まず、現在のページでは、ユーザーがプロフィール ページに移動すると、ホームページに戻る方法がありません。ProfileScreen ウィジェットに AppBar を追加して、この問題を修正します。
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(title: const Text('User Profile')),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
ProfileScreen.appBar
引数は Flutter Material パッケージの AppBar
ウィジェットを受け取るため、作成して Scaffold
に渡した他の AppBar
と同様に扱うことができます。この例では、「戻る」ボタンを自動的に追加するデフォルトの機能が維持され、画面にタイトルが表示されるようになりました。
プロフィール画面にお子様を追加する
ProfileScreen
ウィジェットには、children という名前のオプションの引数もあります。この引数はウィジェットのリストを受け取り、これらのウィジェットは、ProfileScreen
の構築に内部で使用されている Column
ウィジェット内に縦方向に配置されます。ProfileScreen
ビルドメソッドのこの Column
ウィジェットは、渡された子を [ログアウト] ボタンの上に配置します。
home.dart
のコードを更新して、ログイン画面と同様に、ここに会社のロゴを表示します。
lib/home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(title: const Text('User Profile')),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
}),
],
children: [
const Divider(),
Padding(
padding: const EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
),
],
),
),
);
},
),
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
アプリを再読み込みすると、画面に次のように表示されます。
7. マルチプラットフォーム Google 認証ログイン
FlutterFire UI には、Google、Twitter、Facebook、Apple、GitHub などのサードパーティ プロバイダで認証するためのウィジェットと機能も用意されています。
Google 認証と統合するには、公式の firebase_ui_oauth_google プラグインとその依存関係をインストールします。これにより、ネイティブ認証フローが処理されます。ターミナルで、Flutter プロジェクトのルートに移動し、次のコマンドを入力します。
flutter pub add google_sign_in firebase_ui_oauth_google
Google ログイン プロバイダを有効にする
次に、Firebase コンソールで Google プロバイダを有効にします。
- コンソールで [認証ログイン プロバイダ] 画面に移動します。
- [Add new provider](新しいプロバイダを追加)をクリックします。
- [Google] を選択します。
- [有効にする] と表示されたスイッチを切り替え、[保存] を押します。
- 構成ファイルのダウンロードに関する情報が記載されたモーダルが表示されたら、[完了] をクリックします。
- Google ログイン プロバイダが追加されたことを確認します。
Google ログインボタンを追加する
Google ログインを有効にして、ログイン画面に Google ログイン ボタンのスタイル付きの表示に必要なウィジェットを追加します。auth_gate.dart
ファイルに移動し、コードを次のように更新します。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // Add this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: clientId), // Add this line
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
ここで追加された新しいコードは、SignInScreen
ウィジェット構成への GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
の追加のみです。
追加したら、アプリを再読み込みすると、Google ログイン ボタンが表示されます。
ログインボタンを構成する
このボタンは、追加の設定なしでは機能しません。Flutter Web で開発している場合は、この手順を追加するだけで動作します。他のプラットフォームでは追加の手順が必要になります。これについては後ほど説明します。
- Firebase コンソールで [認証プロバイダ] ページに移動します。
- Google プロバイダをクリックします。
- [ウェブ SDK 構成] 展開パネルをクリックします。
- [ウェブ クライアント ID] の値をコピーします。
- テキスト エディタに戻り、この ID を
clientId
という名前のパラメータに渡して、ファイルauth_gate.dart
のGoogleProvider
のインスタンスを更新します。
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
ウェブ クライアント ID を入力したら、アプリを再読み込みします。[Google でログイン] ボタンを押すと、ウェブを使用している場合は新しいウィンドウが表示され、Google ログイン フローが案内されます。最初は次のようになります。
iOS の構成
iOS でこの機能を動作させるには、追加の設定プロセスが必要です。
- Firebase コンソールで [プロジェクトの設定] 画面に移動します。次のような Firebase アプリの一覧が表示されます。
- [iOS] を選択します。アプリケーション名は、スクリーンショットに表示されているものとは異なります。この Codelab で
flutter-codelabs/firebase-auth-flutterfire-ui/start
プロジェクトを使用した場合は、スクリーンショットの「complete」が「start」になります。 GoogleServices-Info.plist
と表示されているボタンをクリックして、必要な構成ファイルをダウンロードします。- ダウンロードしたファイルを Flutter プロジェクトの
/ios/Runner
というディレクトリにドラッグします。 - プロジェクトのルートから次のターミナル コマンドを実行して、Xcode を開きます。
open ios/Runner.xcworkspace
- Runner ディレクトリを右クリックして、[Add Files to "Runner"] を選択します。
- ファイル マネージャーで
GoogleService-Info.plist
を選択します。 - (Xcode 以外の)テキスト エディタに戻り、以下の
CFBundleURLTypes
属性をios/Runner/Info.plist
ファイルに追加します。<!-- Put me in the [my_project]/ios/Runner/Info.plist file --> <!-- Google Sign-in Section --> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLSchemes</key> <array> <!-- TODO Replace this value: --> <!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID --> <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string> </array> </dict> </array> <!-- End of the Google Sign-in Section -->
- ウェブ設定で追加した
GoogleProvider.clientId
を、Firebase iOS クライアント ID に関連付けられたクライアント ID に置き換える必要があります。まず、この ID はfirebase_options.dart
ファイルのiOS
定数の一部として確認できます。iOSClientId
に渡された値をコピーします。static const FirebaseOptions ios = FirebaseOptions( apiKey: 'YOUR API KEY', appId: 'YOUR APP ID', messagingSenderId: '', projectId: 'PROJECT_ID', storageBucket: 'PROJECT_ID.firebasestorage.app', iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here. iosBundleId: 'com.example.BUNDLE', );
- この値を
lib/main.dart
ファイルのclientId
変数に貼り付けます。
lib/main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart';
const clientId = 'YOUR_CLIENT_ID'; // Replace this value with your Client ID.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp(clientId: clientId));
}
Flutter アプリがすでに iOS で実行されている場合は、完全にシャットダウンしてから、アプリケーションを再度実行する必要があります。それ以外の場合は、iOS でアプリを実行します。
8. 完了
Firebase Auth UI for Flutter の Codelab を完了しました。この Codelab の完成版のコードは、GitHub の firebase-auth-flutterfire-ui/complete
ディレクトリにあります。
学習した内容
- Firebase を使用するように Flutter アプリを設定する
- Firebase コンソールで Firebase プロジェクトを設定する
- FlutterFire CLI
- Firebase CLI
- Firebase Authentication の使用
- FlutterFire UI を使用して Flutter アプリで Firebase 認証を処理する
次のステップ
- Flutter で Firestore と Authentication を使用する方法の詳細については、Firebase for Flutter を理解する Codelab をご覧ください。
- Flutter アプリケーションの構築に役立つ他の Firebase ツールを確認する:
詳細
- Firebase サイト: firebase.google.com
- Flutter サイト: flutter.dev
- FlutterFire Firebase Flutter ウィジェット: firebase.flutter.dev
- Firebase の YouTube チャンネル
- Flutter の YouTube チャンネル
Sparky がお祝いに駆けつけました。