モチベーション
- Flutter WebでのFirebaseAuthライブラリ(
firebase_auth_web
)の挙動が気色悪いため、場当たり的な解決になってしまった - バグっぽい挙動にも思えるが、一旦現在の状態で解決索を備忘しておく
環境
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, 1.24.0-10.2.pre, on Mac OS X 10.15.7 19H15 darwin-x64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 12.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.1)
[✓] VS Code (version 1.51.1)
[✓] Connected device (4 available)
最初に観測された現象
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
debugPrint('currentUser: ${FirebaseAuth.instance.currentUser?.email}');
runApp(MyApp());
}
- Chromeでのデバッグ中にHotReloadする分には特におかしな挙動はなかった。
- まぁもともとHot Reloadちょいちょい失敗するのは置いといて
しかし、ブラウザをリロードするとcurrentUser
がnull
になる
currentUser: null
renderLoginPage ←ログインページがbuildされた
firebase_auth_web
にはsetPersistent
があったのを思い出す
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// 追加
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
debugPrint('currentUser: ${FirebaseAuth.instance.currentUser?.email}');
runApp(MyApp());
}
ログイン後にブラウザリロードしてみる
currentUser: null
renderLoginPage
だめじゃん🤔
よくわからないのでStream<User> authStateChanges
を観測してみる
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
// 追加
FirebaseAuth.instance.authStateChanges().listen((event) {
debugPrint('authStateChanges: ${event?.email}');
});
debugPrint('currentUser: ${FirebaseAuth.instance.currentUser?.email}');
runApp(MyApp());
}
ログイン後にブラウザリロードすると
currentUser: null
authStateChanges: null
renderLoginPage
うん、知ってた
しかし、この後にHotRestartをすると...
currentUser: rr.yamamoto@gmail.com
authStateChanges: rr.yamamoto@gmail.com
renderTodoPage ←ログイン後の画面ちゃんと出た
🤔🤔🤔🤔🤔🤔???
-
setPersistence(Persistence.LOCAL)
は一応、効いてるっぽい?
よくわからないのでStream<User> userChanges
も観測してみる
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
FirebaseAuth.instance.authStateChanges().listen((event) {
debugPrint('authStateChanges: ${event?.email}');
});
// 追加
FirebaseAuth.instance.userChanges().listen((event) {
debugPrint('userChanges: ${event?.email}');
});
debugPrint('currentUser: ${FirebaseAuth.instance.currentUser?.email}');
runApp(MyApp());
}
ログイン後にブラウザリロードすると
currentUser: null
authStateChanges: null
userChanges: null
renderLoginPage
userChanges: rr.yamamoto@gmail.com ←🤔🤔🤔🤔🤔🤔🤔🤔
画面的にはログイン画面が出たまま。
つまり、レンダリング後にcurrentUser
が復活している
→currentUserの復帰処理が、runApp()
に間に合ってない...?
そんなら雑にFuture.delayedで2秒待ってみる
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
FirebaseAuth.instance.authStateChanges().listen((event) {
debugPrint('authStateChanges: ${event?.email}');
});
FirebaseAuth.instance.userChanges().listen((event) {
debugPrint('userChanges: ${event?.email}');
});
debugPrint('currentUser: ${FirebaseAuth.instance.currentUser?.email}');
// 追加してみるが、ほんまかいな?
await Future.delayed(Duration(seconds: 2));
runApp(MyApp());
}
ほんまやった
currentUser: null
authStateChanges: null
userChanges: null
userChanges: rr.yamamoto@gmail.com
renderTodoPage ←ちゃんとログイン後ページ出てる
そして...
みなさんお気づきだろうか...「***authStateChangesが飛んでこない」***ことに
結論
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
if (FirebaseAuth.instance.currentUser == null) {
// 2秒過ぎるかcurrentUserが復帰してきたらレンダリング開始
await Future.any([
FirebaseAuth.instance.userChanges().firstWhere((u) => u != null),
Future.delayed(Duration(milliseconds: 2000)),
]);
}
runApp(MyApp());
- ブラウザリロードされると、HotRestartしたのと同じ状態になる
-
setPersistence
しててもmain直後はcurrentUser
はnull
- しかし1.5秒程でひっそりとcurrentUserは戻っている。
- このとき
userChanges
は反応するが、authStateChanges
には何も来ない -
authStateChanges
は、ブラウザリロード直後は信用ならない- initalizeAppをindex.htmlでやってるから??
とりあえずリロードでどっかいっちゃう問題は解消したが、どうみても嘘くさい解決方法なので真似しないように
- 本格的に本家のソース追っかけないとわからんちん誰かよろしく