Flutterfire: Document correct place to add Firebase.initializeApp();

Created on 28 Aug 2020  路  10Comments  路  Source: FirebaseExtended/flutterfire

Hi, the problem I'm having is that every time the app starts, a black screen is shown for a split second between the splashScreen and the first page of the app.

This happens when firebase changes to the ConnectionState.done state, and switches between one widget and another.

class FlutterFireInit extends StatelessWidget {
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();
  final Widget child;
  FlutterFireInit({Key key, @required this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      // Initialize FlutterFire
      future: _initialization,
      builder: (context, snapshot) {
        // Check for errors
        if (snapshot.hasError) {
          // return SomethingWentWrong();
          print('Something went wrong in Flutter Fire');
        }

        // Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) {
          print('firebase INIT');
          return child;
        }

        // Otherwise, show something whilst waiting for initialization to complete
        print('firebase not Init');
        return Container(
          height: double.infinity,
          width: double.infinity,
          color: Color.fromRGBO(34, 36, 49, 1),
          alignment: Alignment.bottomCenter,
        );
      },
    );
  }
}

Flutter doctor

Run flutter doctor and paste the output below:

Doctor summary (to see all details, run flutter doctor -v):
[鉁揮 Flutter (Channel stable, 1.20.2, on Mac OS X 10.15.6 19G73, locale es-ES)

[鉁揮 Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[鉁揮 Xcode - develop for iOS and macOS (Xcode 11.6)
[鉁揮 Android Studio (version 4.0)
[鉁揮 VS Code (version 1.48.2)
[!] Connected device
    ! No devices available

! Doctor found issues in 1 category.
core documentation

Most helpful comment

Hi @Flucadetena

Please try code sample


code sample

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      theme: ThemeData.dark(),
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Material App Bar'),
      ),
      body: Center(
        child: Container(
          child: Text('Hello World'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {},
      ),
    );
  }
}

firebase_core: ^0.5.0

All 10 comments

The problem might be that you are waiting for the FirebaseApp to initialize but your main function is calling runApp immediately. Try adding this as the first line of your main function (before calling runApp):
WidgetsFlutterBinding.ensureInitialized();

@mbilalakmal that does not change anything. I have the same problem

Hi @mbilalakmal that is not the problem. The problem is the complete rebuild of the widget tree as it changes when firebase is init.

I'm think there maybe a way of covering this with a transition or animation, instead of changing, hiding the widget but I have to try it.

Even if this works, it is not a good solution.

@Flucadetena I found the fix. The fix for me was the following:

add the following to your android manifest and make sure you have splash screen.

<meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <meta-data
                    android:name="io.flutter.embedding.android.SplashScreenDrawable"
                    android:resource="@drawable/launch_background"
            />

https://flutter.dev/docs/development/ui/advanced/splash-screen#the-flutter-splash-screen

@Flucadetena can you try above solution and see if it works for you ?
Thanks.

Hi @pratikpparikh and @darshankawar If tried it and didn't solve my problem. As the Flutter app does paint a frame before the blank screen.
I guess I could create a custom SplashScreen connected to a flutter activity and run it until firebase is init, but that is not how it should work and IOS would still have the same problem.

Thanks anyway for the time :)

@Flucadetena
I think you should initialize before runApp, do you still see blank when you initialize in main? StatelessWidget isn't the place to do it

Can you please provide a minimal complete reproducible code sample
Thank you

Hi @TahaTesser I'll try to do it before runApp and get back to you. But that shouldn't be a necessary thing or at least the docs should specify it.

To reproduce the error you simply have to wrap the MyApp Widget with the FlutterFireInit Widget I posted before.

void main() =>
    runApp(FlutterFireInit(child: MyApp()));

Right now I have that widget as a StatefulWidget like so:

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

class FlutterFireInit extends StatefulWidget {
  final Widget child;
  const FlutterFireInit({Key key, @required this.child}) : super(key: key);

  @override
  _FlutterFireInitState createState() => _FlutterFireInitState();
}

class _FlutterFireInitState extends State<FlutterFireInit> {
  Future<FirebaseApp> _initialization;

  @override
  void initState() {
    _initialization = Firebase.initializeApp();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      // Initialize FlutterFire
      future: _initialization,
      builder: (context, snapshot) {
        // Check for errors
        if (snapshot.hasError) {
          // return SomethingWentWrong();
          print('Something went wrong in Flutter Fire');
        }

        //TODO: See what to do with this
        // Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) {
          return widget.child;
        }

        // Otherwise, show something whilst waiting for initialization to complete
        //TODO: Change for splash just in case
        return Container(
          color: Colors.blue,
        );
      },
    );
  }
}

Hi @Flucadetena

Please try code sample


code sample

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      theme: ThemeData.dark(),
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Material App Bar'),
      ),
      body: Center(
        child: Container(
          child: Text('Hello World'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {},
      ),
    );
  }
}

firebase_core: ^0.5.0

Thanks a lot @TahaTesser!! :) This solved my problem, it should be added to the docs as the way to initialize Firebase. Can you change this to a request to be added to the docs? Or should I open a new Issue.

Thanks again this really help.

Was this page helpful?
0 / 5 - 0 ratings