简体   繁体   中英

How to initialize Firebase via Riverpod's FutureProvider

First step in using Firebase within Flutter app is to perform initialization.

I've tried doing this within main() and it works

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp()); 
}

I've utilized Riverpod for state management - with Provider for firebase instance and access to the class with connection methods (Signin, Signout...) and StreamProvider for user state. Again this works fine - recognizing when the user has signed in or signed out - rebuilding widgets and redirecting to proper screen...

Now I would like to also move the code pasted above from main() into a provider definition and have shown proper screen depending on the status of firebase initialization.

I've seen official Firebase example suggesting to use FutureBuilder for this - however, since I've used Riverpod - my idea was to use FutureProvider for initializing firebase. However, whatever I try the app keeps crashing with some null exceptions.

If anybody can share their example of firebase.initializeApp() via FutureProvider it would be great.

I do it like this: (Can be done via singleton if needed)

// services_initialization.dart
class ServiceInit{
  ServiceInit(ProviderContainer container) {
    _container = container;
  }

  // The container is needed to access the ref and load other providers, if required
  late final ProviderContainer _container;

  Future<void> init() async {
    await _initFirebase();
    // initialization of other services, example:
    await _container.read(somethingFutureProvider.future);
  }

  Future<void> _initFirebase() async {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );
  }
}

The main file looks like this:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final _container = ProviderContainer();
  await ServiceInit(_container).init();

  runApp(UncontrolledProviderScope(
      container: _container,
      child: WeatherMain(),
    ),
}

I've found a solution for this so pasting it bellow. Big thanks to 2002Bishwajeet who posted a Firebase & Riverpod authentication example covering this topic as well at GitHub

The idea is to create FutureProvider like this:

final firebaseInitProvider = FutureProvider<FirebaseApp>((ref) async 
{ 
  return await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
});

In the main() keep just WidgetsFlutterBinding.ensureInitialized() Like this:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(ProviderScope(child: const MyApp()));
} 

Then watch the provider and use.when() to show the correct screen - basically to move to AuthenticationWrapper widget only once the Firebase.initializeApp() has completed the initialization process.

Like this:

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final _initializeFirebase = ref.watch(firebaseInitProvider);

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Firebase Authentication App',
      theme: CommonTheme().mainThemeData,
      home: _initializeFirebase.when(
        data: (data) => const AuthenticationWrapper(),
        loading: () => const ProgressScreen(),
        error: (error, stackTrace) => ErrorScreen(error.toString()),
      ),
    );
  }
}

And finally the AuthenticationWrapper is handling display of SignIn or Home screen - depending on the status of the user (already signed in at Firebase Auth or not).

Like this:

class AuthenticationWrapper extends ConsumerWidget {
  const AuthenticationWrapper({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final _authState = ref.watch(authStateProvider);

    return _authState.when(
      data: (value) {
        if (value != null) {
          return HomeScreen();
        } else {
          return LoginScreen();
        }
      },
      error: ((error, stackTrace) => ErrorScreen(error.toString())), //TO-DO set user oriented error messages
      loading: (() => ProgressScreen()),
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM