Skip to content

Commit

Permalink
fix(auth, web): currentUser is now populated right at the start of …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Lyokone committed Dec 5, 2022
1 parent 185e07a commit 2bd0dbf
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 10 deletions.
Expand Up @@ -89,7 +89,9 @@ class FirebaseAuthWeb extends FirebaseAuthPlatform {

/// Called by PluginRegistry to register this plugin for Flutter Web
static void registerWith(Registrar registrar) {
FirebaseCoreWeb.registerService('auth');
FirebaseCoreWeb.registerService('auth', () async {
await FirebaseAuthWeb.instance.delegate.onWaitInitState();
});
FirebaseAuthPlatform.instance = FirebaseAuthWeb.instance;
PhoneMultiFactorGeneratorPlatform.instance = PhoneMultiFactorGeneratorWeb();
RecaptchaVerifierFactoryPlatform.instance =
Expand Down
24 changes: 24 additions & 0 deletions packages/firebase_auth/firebase_auth_web/lib/src/interop/auth.dart
Expand Up @@ -362,6 +362,28 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {

auth_interop.AuthSettings get settings => jsObject.settings;

User? _initUser;

/// On web we need to wait for the first onAuthStateChanged event to fire
/// in order to be sure that the currentUser is set.
/// To preserve behavior on web and mobile we store the initial user
/// in `_initUser` and add it manually to the `_changeController`.
Future<void> onWaitInitState() async {
final completer = Completer();
final nextWrapper = allowInterop((auth_interop.UserJsImpl? user) {
_initUser = User.getInstance(user);
completer.complete();
});

final errorWrapper = allowInterop((e) => _changeController!.addError(e));

final unsubscribe = jsObject.onAuthStateChanged(nextWrapper, errorWrapper);

await completer.future;

unsubscribe();
}

Func0? _onAuthUnsubscribe;
// TODO(rrousselGit): fix memory leak – the controller isn't closed even in onCancel
// ignore: close_sinks
Expand Down Expand Up @@ -397,6 +419,8 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
onCancel: stopListen,
sync: true,
);

_changeController!.add(_initUser);
}
return _changeController!.stream;
}
Expand Down
Expand Up @@ -14,23 +14,44 @@ class FirebaseWebService {
/// property allows overriding of web naming to Flutterfire plugin naming.
String? override;

/// Function to call to ensure the Firebase Service is initalized.
/// Usually used to ensure that the Web SDK match the behavior
/// of native SDKs.
EnsurePluginInitialized ensurePluginInitialized;

/// Creates a new [FirebaseWebService].
FirebaseWebService._(this.name, [this.override]);
FirebaseWebService._(
this.name, {
this.override,
this.ensurePluginInitialized,
});
}

typedef EnsurePluginInitialized = Future<void> Function()?;

/// The entry point for accessing Firebase.
///
/// You can get an instance by calling [FirebaseCore.instance].
class FirebaseCoreWeb extends FirebasePlatform {
static Map<String, FirebaseWebService> _services = {
'core': FirebaseWebService._('app', 'core'),
'app-check': FirebaseWebService._('app-check', 'app_check'),
'remote-config': FirebaseWebService._('remote-config', 'remote_config'),
'core': FirebaseWebService._('app', override: 'core'),
'app-check': FirebaseWebService._('app-check', override: 'app_check'),
'remote-config':
FirebaseWebService._('remote-config', override: 'remote_config'),
};

/// Internally registers a Firebase Service to be initialized.
static void registerService(String service) {
_services.putIfAbsent(service, () => FirebaseWebService._(service));
static void registerService(
String service, [
EnsurePluginInitialized? ensurePluginInitialized,
]) {
_services.putIfAbsent(
service,
() => FirebaseWebService._(
service,
ensurePluginInitialized: ensurePluginInitialized,
),
);
}

/// Registers that [FirebaseCoreWeb] is the platform implementation.
Expand Down Expand Up @@ -251,6 +272,18 @@ class FirebaseCoreWeb extends FirebasePlatform {
}
}

await Future.wait(
_services.values.map((service) {
final ensureInitializedFunction = service.ensurePluginInitialized;

if (ensureInitializedFunction == null) {
return Future.value();
}

return ensureInitializedFunction();
}),
);

return _createFromJsApp(app!);
}

Expand Down
5 changes: 2 additions & 3 deletions packages/firebase_ui_auth/example/lib/main.dart
Expand Up @@ -5,19 +5,18 @@
import 'package:firebase_auth/firebase_auth.dart'
hide PhoneAuthProvider, EmailAuthProvider;
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
import 'package:firebase_ui_oauth_apple/firebase_ui_oauth_apple.dart';
import 'package:firebase_ui_oauth_facebook/firebase_ui_oauth_facebook.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
import 'package:firebase_ui_oauth_twitter/firebase_ui_oauth_twitter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

import 'firebase_options.dart';

import 'config.dart';
import 'decorations.dart';
import 'firebase_options.dart';

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

0 comments on commit 2bd0dbf

Please sign in to comment.