Skip to content

Commit 2bd0dbf

Browse files
authored
fix(auth, web): currentUser is now populated right at the start of the application without needing to wait for authStateChange (#10028)
* feat: add new init function for auth * feat: add new init function for auth * feat: add new init function for auth * fix(auth, web): fix formatting * feat: change naming * feat: fix tests * feat: add new init function for auth
1 parent 185e07a commit 2bd0dbf

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

Diff for: packages/firebase_auth/firebase_auth_web/lib/firebase_auth_web.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ class FirebaseAuthWeb extends FirebaseAuthPlatform {
8989

9090
/// Called by PluginRegistry to register this plugin for Flutter Web
9191
static void registerWith(Registrar registrar) {
92-
FirebaseCoreWeb.registerService('auth');
92+
FirebaseCoreWeb.registerService('auth', () async {
93+
await FirebaseAuthWeb.instance.delegate.onWaitInitState();
94+
});
9395
FirebaseAuthPlatform.instance = FirebaseAuthWeb.instance;
9496
PhoneMultiFactorGeneratorPlatform.instance = PhoneMultiFactorGeneratorWeb();
9597
RecaptchaVerifierFactoryPlatform.instance =

Diff for: packages/firebase_auth/firebase_auth_web/lib/src/interop/auth.dart

+24
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,28 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
362362

363363
auth_interop.AuthSettings get settings => jsObject.settings;
364364

365+
User? _initUser;
366+
367+
/// On web we need to wait for the first onAuthStateChanged event to fire
368+
/// in order to be sure that the currentUser is set.
369+
/// To preserve behavior on web and mobile we store the initial user
370+
/// in `_initUser` and add it manually to the `_changeController`.
371+
Future<void> onWaitInitState() async {
372+
final completer = Completer();
373+
final nextWrapper = allowInterop((auth_interop.UserJsImpl? user) {
374+
_initUser = User.getInstance(user);
375+
completer.complete();
376+
});
377+
378+
final errorWrapper = allowInterop((e) => _changeController!.addError(e));
379+
380+
final unsubscribe = jsObject.onAuthStateChanged(nextWrapper, errorWrapper);
381+
382+
await completer.future;
383+
384+
unsubscribe();
385+
}
386+
365387
Func0? _onAuthUnsubscribe;
366388
// TODO(rrousselGit): fix memory leak – the controller isn't closed even in onCancel
367389
// ignore: close_sinks
@@ -397,6 +419,8 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
397419
onCancel: stopListen,
398420
sync: true,
399421
);
422+
423+
_changeController!.add(_initUser);
400424
}
401425
return _changeController!.stream;
402426
}

Diff for: packages/firebase_core/firebase_core_web/lib/src/firebase_core_web.dart

+39-6
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,44 @@ class FirebaseWebService {
1414
/// property allows overriding of web naming to Flutterfire plugin naming.
1515
String? override;
1616

17+
/// Function to call to ensure the Firebase Service is initalized.
18+
/// Usually used to ensure that the Web SDK match the behavior
19+
/// of native SDKs.
20+
EnsurePluginInitialized ensurePluginInitialized;
21+
1722
/// Creates a new [FirebaseWebService].
18-
FirebaseWebService._(this.name, [this.override]);
23+
FirebaseWebService._(
24+
this.name, {
25+
this.override,
26+
this.ensurePluginInitialized,
27+
});
1928
}
2029

30+
typedef EnsurePluginInitialized = Future<void> Function()?;
31+
2132
/// The entry point for accessing Firebase.
2233
///
2334
/// You can get an instance by calling [FirebaseCore.instance].
2435
class FirebaseCoreWeb extends FirebasePlatform {
2536
static Map<String, FirebaseWebService> _services = {
26-
'core': FirebaseWebService._('app', 'core'),
27-
'app-check': FirebaseWebService._('app-check', 'app_check'),
28-
'remote-config': FirebaseWebService._('remote-config', 'remote_config'),
37+
'core': FirebaseWebService._('app', override: 'core'),
38+
'app-check': FirebaseWebService._('app-check', override: 'app_check'),
39+
'remote-config':
40+
FirebaseWebService._('remote-config', override: 'remote_config'),
2941
};
3042

3143
/// Internally registers a Firebase Service to be initialized.
32-
static void registerService(String service) {
33-
_services.putIfAbsent(service, () => FirebaseWebService._(service));
44+
static void registerService(
45+
String service, [
46+
EnsurePluginInitialized? ensurePluginInitialized,
47+
]) {
48+
_services.putIfAbsent(
49+
service,
50+
() => FirebaseWebService._(
51+
service,
52+
ensurePluginInitialized: ensurePluginInitialized,
53+
),
54+
);
3455
}
3556

3657
/// Registers that [FirebaseCoreWeb] is the platform implementation.
@@ -251,6 +272,18 @@ class FirebaseCoreWeb extends FirebasePlatform {
251272
}
252273
}
253274

275+
await Future.wait(
276+
_services.values.map((service) {
277+
final ensureInitializedFunction = service.ensurePluginInitialized;
278+
279+
if (ensureInitializedFunction == null) {
280+
return Future.value();
281+
}
282+
283+
return ensureInitializedFunction();
284+
}),
285+
);
286+
254287
return _createFromJsApp(app!);
255288
}
256289

Diff for: packages/firebase_ui_auth/example/lib/main.dart

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@
55
import 'package:firebase_auth/firebase_auth.dart'
66
hide PhoneAuthProvider, EmailAuthProvider;
77
import 'package:firebase_core/firebase_core.dart';
8-
import 'package:flutter/material.dart';
98
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
109
import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
1110
import 'package:firebase_ui_oauth_apple/firebase_ui_oauth_apple.dart';
1211
import 'package:firebase_ui_oauth_facebook/firebase_ui_oauth_facebook.dart';
1312
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
1413
import 'package:firebase_ui_oauth_twitter/firebase_ui_oauth_twitter.dart';
14+
import 'package:flutter/material.dart';
1515
import 'package:flutter_localizations/flutter_localizations.dart';
1616

17-
import 'firebase_options.dart';
18-
1917
import 'config.dart';
2018
import 'decorations.dart';
19+
import 'firebase_options.dart';
2120

2221
final actionCodeSettings = ActionCodeSettings(
2322
url: 'https://flutterfire-e2e-tests.firebaseapp.com',

0 commit comments

Comments
 (0)