4

While Firebase.initializeApp() only needs to be called once, are there negative consequences for calling it twice?

Background: I'm troubleshooting a [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() error and temporarily fixed it by adding await Firebase.initializeApp(); in void main() async in addition to my pre-existing final Future<FirebaseApp> _fbApp = Firebase.initializeApp();

Everything seems to work okay now. I intend to fix it, but if calling Firebase.initializeApp() twice isn't hurting anything, I can stick with my immediate priorities and move forward.

Here's the relevant block of code:

void main() async {
  WidgetsFlutterBinding
      .ensureInitialized(); // added per https://stackoverflow.com/questions/57689492/flutter-unhandled-exception-servicesbinding-defaultbinarymessenger-was-accesse
  await Firebase
      .initializeApp(); 
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final Future<FirebaseApp> _fbApp = Firebase
      .initializeApp(); // changed from "async {  await Firebase.initializeApp();" per official "Getting started with Firebase on Flutter - Firecasts" video at https://youtu.be/EXp0gq9kGxI?t=920
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return StreamProvider<Userrr>.value(
      value: AuthService().user,
      // above specifies what stream we want to listen to and what data we expect to get back
      child: MaterialApp(

Thanks!

UPDATE: I tried all the good advice below and nothing seemed to work. I think my code, an exact duplication from two tutorials (one for getting started with Firebase and another for Firebase auth 101) had one or more gaps because of package updates or other incompatibilities.

I went back to basics and wrote-out by hand and re-implemented every step for installing and setting-up Firebase Core from the official "FlutterFire Overview."

I re-read all the documentation, as suggested below.

I updated all packages, including firebase_auth: “^0.20.0" to firebase_auth: “^0.20.0+1" (the +1 change is to “FIX: package compatibility,” per the changelog).

And then finally, I created a backup of main.dart as old_main.dart, then copy-pasted the exact "Initializing FlutterFire" FurtureBuilder code, then carefully replaced each part of that generic code with my own. Here is each item I replaced:

// replaced "_initialization" with "_fbApp"
// replaced if (snapshot.hasError) ... "return SomethingWentWrong();" with the response from below
// replaced "return Loading();" with CircularProgressIndicator form below
// changed return MyAwesomeApp(); to return MyApp();
// changed "class App extends StatelessWidget" to "class MyApp extends StatelessWidget
// replaced "MyAwesomeApp();" from "if (snapshot.connectionState == ConnectionState.done) { return MyAwesomeApp();" with all the "StreamProvider<Userrr>.value(..." code EXCEPT changed home to "home: Wrapper(),"

It may seem elementary, but for a novice like myself, it was the only way forward. Thankfully it worked!

Here's the full working code excerpt:

void main() {
  WidgetsFlutterBinding
      .ensureInitialized(); // added by mgav, per https://stackoverflow.com/questions/57689492/flutter-unhandled-exception-servicesbinding-defaultbinarymessenger-was-accesse
  // await Firebase.initializeApp(); // added by mgav to test, KNOWING the Firebase is already initialized as a future below in line 25. Was trying to test (temp?) fix for error: “[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()  The relevant error-causing widget was:  MyApp file:///Users/mgav/AndroidStudioProjects/brand_new_flutter_app/lib/main.dart:21:10”
  runApp(MyApp());
}

// BEGIN Firebase FutureBuilder code pasted from docs at https://firebase.flutter.dev/docs/overview/#initializing-flutterfire (replaces next section of commented-out code)
class MyApp extends StatelessWidget {
  // Create the initialization Future outside of `build`:
  final Future<FirebaseApp> _fbApp = Firebase.initializeApp();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      // Initialize FlutterFire:
      future: _fbApp,
      builder: (context, snapshot) {
        // Check for errors
        if (snapshot.hasError) {
          print('You have an error! ${snapshot.error.toString()}');
          return Text('Something went wrong main.dart around line 48');
        }

        // Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) {
          return StreamProvider<Userrr>.value(
            value: AuthService().user,
            // above specifies what stream we want to listen to and what data we expect to get back
            child: MaterialApp(
              title: 'Real Revs and Q&A',
              theme: ThemeData(
                primarySwatch: Colors.blueGrey,
                visualDensity: VisualDensity.adaptivePlatformDensity,
              ),
              routes: {
                // '/welcome': (context) => WelcomeScreen(),
                '/cleanwritereview': (context) => CleanWriteReviewScreen(),
                '/registrationscreen': (context) => RegistrationScreen(),
                '/loginscreen': (context) => LoginScreen(),
                '/viewreviewsscreen': (context) => ViewReviewsScreen(),
                '/homescreen': (context) => Home(),
              },
              home: Wrapper(),
            ),
          );
        }

        // Otherwise, show something whilst waiting for initialization to complete
        return Center(
          child: CircularProgressIndicator(),
        );
      },
    );
  }
}
Mark Gavagan
  • 878
  • 12
  • 45
  • In your pre-existing `_fbApp` implementation, did you wait for its result using a `FutureBuilder` before? – rickimaru Jan 16 '21 at 00:01

3 Answers3

2

You'll get an error message if you call initializeApp() twice for the same FirebaseApp.

In your case, you can get the app that you've already created with:

final FirebaseApp _fbApp = Firebase.app();

Also see the documentation on FlutterFire, specifically initializing and using FirebaseApp.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thank you. I tried your suggestion by commenting-out the first ```await Firebase.initializeApp();``` and replacing ```final Future _fbApp = Firebase.initializeApp();``` and received this error: ```Error: A value of type 'FirebaseApp' can't be assigned to a variable of type 'Future'. - 'FirebaseApp' is from 'package:firebase_core/firebase_core.dart' ('../../Developer/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.7.0/lib/firebase_core.dart'). - 'Future' is from 'dart:async'. final Future _fbApp = Firebase.app();``` – Mark Gavagan Jan 16 '21 at 12:15
  • And, as expected, when I change your proposed ```final Future _fbApp = Firebase.app();``` back to my original ```final Future _fbApp = Firebase.initializeApp();``` the error I was originally trying to fix - ```The following FirebaseException was thrown building MyApp(dirty): [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()``` - resumes. – Mark Gavagan Jan 16 '21 at 12:25
  • 1
    On your first comment: `firebase.app()` doesn't return a `Future`: https://pub.dev/documentation/firebase_core/latest/firebase_core/Firebase/app.html. So I had forgotten to modify the type from your code in my answer. I updated it now, but highly recommend getting comfortable enough with the (reference) documentation I linked to be able to spot such mistakes yourself. – Frank van Puffelen Jan 16 '21 at 15:16
  • .@Frank van Puffelen, I was offline and will be digging-into and responding to every answer today. Thanks! – Mark Gavagan Jan 18 '21 at 14:58
1

To initialise firebase you either do:

main(){
 await Firebase.initializeApp(); // don't run the app until firebase is initialized
 runApp(MyApp());
}

Or use a FutureBuilder which ensure the future is resolved before running the code inside the builder function.

  @override
  Widget build(BuildContext context) {
    final _fbApp = Firebase.initializeApp();
    return FutureBuilder(
        future: _fbApp, 
        builder: (context, snapshot) { // waits until _fbApp is resolved to execute.
          .... 
        });
  }

You get an error because you don't await _fbApp future.

In your code there is no guarantee AuthService().user is executed after initializeApp has finished. To garantee this you have to wait until initializeApp() is resolved by using await, then or a FutureBuilder.

bouraine
  • 61
  • 3
0

Add a try catch to understand why the first call in initializeApp is not working.

Firebase initialises its core services only once. there is exactly one FirebaseApp instance by name. When you don't specify the name '[DEFAULT]' is used.

Try doing this:

final app = await Firebase.initializeApp();
final app2 = await Firebase.initializeApp();
print(app == app2); // is true

Please provide more details on your setup:

  • firebase_auth, firebase_core versions,
  • Execution plateform (Android, ios or web).

In the last version of fire_auth we use:

FirebaseAuth.instance.authStateChanges // stream to subscribe to the user's current authentication state.
  
bouraine
  • 61
  • 3
  • Thank you. The first call - ```await Firebase.initializeApp();``` - IS working, but I only added it, as a temporary fix, after the one that's subsequent in the code - ```final Future _fbApp = Firebase.initializeApp();``` - which I changed from ```await Firebase.initializeApp();``` per Google Firebase's official "Getting started with Firebase on Flutter - Firecasts" video at https://youtu.be/EXp0gq9kGxI?t=920 – Mark Gavagan Jan 16 '21 at 12:33
  • And thank you also for your catch on ```return StreamProvider.value( value: AuthService().user,``` I am using ```authStateChanges()``` elsewhere in ```Stream get user { return _auth.authStateChanges().map(_userFromFirebaseUser);``` but now I know I have to figure out how to fix it in the code originally posted above. #helpful – Mark Gavagan Jan 16 '21 at 13:00
  • I'm a little trapped between the official Google Firebase video tutorial mentioned above, this one on an auth change user stream, to detect auth changes (https://www.youtube.com/watch?v=LkpPEYuqbIY), and the underlying Firebase code being updated. It's tough for a novice like me, but I'm grateful for your and others' help! – Mark Gavagan Jan 16 '21 at 13:05
  • you need this line `final Future _fbApp = Firebase.initializeApp();`only if you use a FutureBuilder as shown in youtu.be/EXp0gq9kGxI?t=920, otherwise use await. i made another answer on your post to explain why (See above). – bouraine Jan 16 '21 at 21:08