skip to Main Content

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.

2

Answers


  1. Chosen as BEST ANSWER

    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()),
        );
      }
    }
    

  2. 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(),
        ),
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search