🚀
[Flutter] firebase_ui_authとriverpod_generator , go_routerでAuth
はじめに
Flutterfire_uiがdeprecatedになるらしく、同じinvertase社がメンテしているfirebase_ui_authを使ってみました。以前と少し使い方が異なっていたため、こちらに記述していきます。
また、こちらではriverpod_generator
を使用しています。少し約束事が増えますが、関数的にプロバイダを定義できるのでとても使いやすいです。
コード
main.dart
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseUIAuth.configureProviders([
EmailAuthProvider(),
GoogleProvider(
clientId:
"YOURCLIENTID"),
]);
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
// This widget is the root of your application.
Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider);
return MaterialApp.router(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate
],
supportedLocales: const [Locale("en"), Locale("ja")],
theme: lightTheme,
darkTheme: darkTheme,
routeInformationProvider: router.routeInformationProvider,
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
);
}
}
エントリポイント。最初に FirebaseUIAuth.configureProviders
でログインプロバイダを設定する。
router.dart
router.dart
part 'router.g.dart';
GoRouter Router(RouterRef ref) {
final userStream = ref.watch(userStreamProvider);
return GoRouter(
routes: [
GoRoute(
path: MainPage.path,
name: MainPage.path,
builder: (context, state) {
return MainPage(
user: userStream.value!,
);
},
),
GoRoute(
path: SignInPage.path,
name: SignInPage.path,
builder: (context, state) => const SignInPage(),
),
],
redirect: (context, state) async {
print('redirecting...');
//state.sublocが使えなくなったのでstate.matchedLocationを使う
final loggingIn = state.matchedLocation == SignInPage.path;
// print(state.subloc);
if (userStream.value == null) {
return loggingIn ? null : SignInPage.path;
}
// print('proceeding');
if (loggingIn) {
// print('auth success');
return '/';
}
return null;
},
);
}
ここがキモで、ProviderScopeのoverrides
を利用してしまうとGoroute間の値の受け渡し時にエラーになってしまったので、各RouteにコンストラクタとしてuserStream.value!
を渡すことにしています。
usrStream.value!がそもそもないときはredirectでサインインページにredirectします。
sign_in_screen
sign_in_screen.dart
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class SignInPage extends ConsumerWidget {
const SignInPage({Key? key}) : super(key: key);
static const path = '/sign-in';
Widget build(BuildContext context, WidgetRef ref) {
return SignInScreen(
auth: FirebaseAuth.instance,
actions: [
AuthStateChangeAction<SignedIn>((context, state) {
debugPrint("Signed in");
context.go(MainPage.path);
}),
],
);
}
}
firebase_ui_authをこちらで使います。
user.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user.g.dart';
Stream<User?> UserStream(UserStreamRef ref) async* {
await for (final user in FirebaseAuth.instance.authStateChanges()) {
yield user;
}
}
Discussion
TypedShellRoute使ってProtectedPageを定義するとProviderScopeのOverridesが使える。
こっちのが便利かも。