今回は、Flutter と Firebaseを使って匿名認証をやっていこうと思います!
もし、まだFlutterでFirebaseを使えるように設定をしていないの方は、「【Flutter Dart】FirebaseをiOSとAndroidで使えるようにする!」を参考にしてみてください!
匿名認証ってなんじゃ!
学習に使った本はこちら!
Amazon Kindle Unlimited でもFlutter、Dartの本はいっぱいあるぞ!
プラグインを導入する!
早速始めていきましょう!!
Pubspec.yamlを編集
- Pubspec.yamlに利用するプラグインを記載していく。
- 【補足】下記のようなプラグインを利用する予定です。
- 【参考】firebase_auth:Firebase認証の利用
- 【参考】firebase_firestore:クラウドFireStoreの利用
- 【参考】flutter_hooks:State管理でコード量を減らす
- 【参考】hooks_riverpod:State管理でコード量を減らす
- 【参考】freezed:immutable なオブジェクト用のコード生成ができる
- 【参考】freezed_annotation:Freezedアノテーションの提供
- 【参考】build_runner:ファイルやコードを生成する方法を提供する
- 【参考】json_serializable:JSONのシリアライズ・デシリアライズ
name: shopping_list
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
firebase_core: ^1.3.0
firebase_analytics: ^8.1.2
firebase_auth: ^2.0.0
cloud_firestore: ^2.3.0
flutter_hooks: ^0.17.0
hooks_riverpod: ^0.14.0+4
freezed_annotation: ^0.14.2
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.0.6
freezed: ^0.14.2
json_serializable: ^4.1.3
flutter:
uses-material-design: true
- 上記が記載できたら、pubgetをしましょう!
エラーが出た場合は、バージョンを見直してみるのじゃぞ!
FirebaseのAuthenticationを利用!
実際にFirebaseのAuthenticationを使っていきましょう!
Firebaseの初期化とプロバイダーアクセスの設定
Flutterプロジェクトを作成すると、初期のコードが作成されていると思いますが、不必要なところは削除しておきましょう!
- main.dartを下記のように修正する。
import'package:firebase_core/firebase_core.dart';
import'package:flutter/material.dart';
import'package:hooks_riverpod/hooks_riverpod.dart';
//main()を非同期を制御する
void main() async {
//アプリ起動時に処理したいので追記
WidgetsFlutterBinding.ensureInitialized();
//Firebaseの初期化(同期)
await Firebase.initializeApp();
//MyApp()をProviderScopeでラップして、アプリ内のどこからでも全てのプロバイダーにアクセスできるようにする。
runApp(ProviderScope(child:MyApp()));
}
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context){
return MaterialApp(
title:'TeechLab.',
theme:ThemeData(
primarySwatch:Colors.brown,
),
home:Scaffold(),
);
}
}
簡単に説明を記載しておきます。
- WidgetsFlutterBinding.ensureInitialized();
→runApp()をする前にFlutter Engineの機能を利用したい場合に宣言 - await Firebase.initializeApp();
→Firebaseを初期化 - runApp(ProviderScope(child:MyApp()));
→ProviderScopeでラップすることで、アプリ内のどこからでも全てのプロバイダーにアクセスできるようにしています。
Authenticationで匿名認証を有効化
- Firebaseの画面に移動
- メニュー>Authenticationを選択
- 「始める」ボタンを押下
- 著名を有効にして、保存
Authenticationを利用するコードを実装
- lib>repositories>auth_repository.dartを作成
- lib>general_providers.dartを作成
- firebaseAuthのインスタンスを生成
import 'package:firebase_auth/firebase_auth.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
// firebaseAuthのインスタンスを提供
final firebaseAuthProvider = Provider<FirebaseAuth>((ref) => FirebaseAuth.instance);
- BaseAuthRepositoryを定義(詳細はコードのコメントを参照)
- BaseAuthRepositoryをimplementsしたAuthRepositoryを実装(詳細はコードのコメントを参照)
- 【補足】authStateChanges()は、匿名ユーザの初期化、サインイン、サインアウトの際にイベントする。
- 【補足】匿名認証なのでログアウトした場合は、別の匿名ユーザでログインさせている。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shopping_list/general_providers.dart';
import 'custom_exception.dart';
// 抽象クラスを定義
abstract class BaseAuthRepository {
// ログイン状態の確認用(ログイン状態の変更や初期化時にイベントする)
Stream<User?> get authStateChanges;
// サインイン(著名ユーザを作成)
Future<void> signInAnonymously();
// 現在サインインしているユーザを取得する。
User? getCurrentUser();
// ログアウト
Future<void> signOut();
}
// AuthRepositoryを提供し、ref.readを渡してアクセスできるようにする
final authRepositoryProvider = Provider<AuthRepository>((ref) => AuthRepository(ref.read));
// 認証リポジトリクラス
class AuthRepository implements BaseAuthRepository {
// riverpod Reader
// アプリ内の他のプロバイダーを読み取ることを許可
final Reader _read;
const AuthRepository(this._read);
// Readerを利用して、firebaseAuth.instanceにアクセス
@override
Stream<User?> get authStateChanges => _read(firebaseAuthProvider).authStateChanges();
// 匿名ユーザでログイン
@override
Future<void> signInAnonymously() async {
try {
await _read(firebaseAuthProvider).signInAnonymously();
} on FirebaseAuthException catch (e) {
throw CustomException(message: e.message);
}
}
// 既存の匿名ユーザを返却
@override
User? getCurrentUser() {
try {
return _read(firebaseAuthProvider).currentUser;
} on FirebaseAuthException catch (e) {
throw CustomException(message: e.message);
}
}
// サインアウトしたら、新たに匿名ユーザでログインさせる。
@override
Future<void> signOut() async {
try {
// サインアウト
await _read(firebaseAuthProvider).signOut();
// 匿名でサインイン
await signInAnonymously();
} on FirebaseAuthException catch (e) {
throw CustomException(message: e.message);
}
}
}
- repositoriesにcustom_exception.dartを作成
- CustomExceptionを実装
// カスタム例外
class CustomException implements Exception {
final String? message;
const CustomException({this.message = 'Auth Error!'});
@override
String toString() => 'CustomException { message: $message}';
}
- lib>controllersを作成
- controllersにauth_controller.dartを作成
- auth_controller.dartを実装(詳細はコードのコメントを参照)
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shopping_list/repositories/auth_repository.dart';
final authControllerProvider = StateNotifierProvider<AuthController, User?>(
(ref) => AuthController(ref.read)..appStarted(),
);
class AuthController extends StateNotifier<User?> {
final Reader _read;
StreamSubscription<User?>? _authStateChangesSubscription;
AuthController(this._read) : super(null) {
// 受信停止
_authStateChangesSubscription?.cancel();
// 受信開始
_authStateChangesSubscription = _read(authRepositoryProvider)
.authStateChanges
.listen((user) => state = user);
}
// 不要な受信をキャンセルするためにdisposeでキャンセルする
@override
void dispose() {
_authStateChangesSubscription?.cancel();
super.dispose();
}
// アプリ開始
void appStarted() async {
// Currentユーザを取得
final user = _read(authRepositoryProvider).getCurrentUser();
// ログインされていなければ、匿名でサインインしてログインさせる。
if (user == null) {
await _read(authRepositoryProvider).signInAnonymously();
}
}
// サインアウト
void signOut() async {
// サインアウトメソッド
await _read(authRepositoryProvider).signOut();
}
}
- main.dartを修正
import'package:firebase_core/firebase_core.dart';
import'package:flutter/material.dart';
import'package:flutter_hooks/flutter_hooks.dart';
import'package:hooks_riverpod/hooks_riverpod.dart';
import'package:shopping_list/controllers/auth_controller.dart';
//main()を非同期にする
void main() async {
//アプリ起動時に処理したいので追記
WidgetsFlutterBinding.ensureInitialized();
//Firebaseの初期化
await Firebase.initializeApp();
//MyApp()をProviderScopeでラップして、アプリ内のどこからでも全てのプロバイダーにアクセスできるようにする。
runApp(ProviderScope(child:MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context){
return MaterialApp(
title:'TeechLab.',
theme:ThemeData(
primarySwatch:Colors.brown,
),
home:HomeScreen(),
);
}
}
class HomeScreen extends HookWidget{
@override
Widget build(BuildContext context){
final authControllerState = useProvider(authControllerProvider);
return Scaffold (
appBar: AppBar(
title: Text('ShoppingList'),
leading: authControllerState!=null
? IconButton(
onPressed:()=>context.read(authControllerProvider.notifier).signOut(),
icon:Icon(Icons.logout)
)
: null,
),
);
}
}
ちゃんとできてるんじゃろな?
動作確認してみよう!
ここまでできたら動作確認して見ましょう!
アプリを起動
- シュミレータを起動(iOSでもAndroidでも構いません。今回はiOSで確認しております。)
- Firebaseを確認してみる
- 匿名ユーザが作成されていることを確認
ログアウトを確認
- ログインされていると思うので、ログアウトボタンを押下
- ログアウトすると、再度ログインされることを確認
- Firebaseでログアウトするたび(再度ログインするたび)匿名ユーザが作成されることを確認
できたぞーー
まとめ
今回は、FirebaseのAuthenticationを使った匿名認証をやっていきました。
次回は、FirebaseのFireStoreを使っていこうと思いますので興味がある方はぜひ参考にしてみてください。
また、今回Flutterを勉強するにあたり利用した教材をあげています。
主に本とUdemyの動画教材を利用しています。興味ある方は、本やUdemyを購入して勉強してみることをおすすめします。
学習に使った本はこちら!
Amazon Kindle Unlimited でもFlutter、Dartの本はいっぱいあるぞ!