is it ok to call firebase.initializeApp() in the main [duplicate] - firebase

This question already has answers here:
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase
(27 answers)
Closed 2 years ago.
flutterfire recently introduced some changes and one of those is the need to call initializeApp() before using any plugin.
is it ok to call it in the main ? something like this :
void main() async {
await Firebase.initializeApp();
return runApp(App());
}
or maybe like this without async await
void main() {
Firebase.initializeApp();
return runApp(App());
}
i think the first example is more correct but its blocking the execution of the main and i have no idea how much time before the future complete?

The only requirement from Firebase is that you call Firebase.initializeApp() before any other Firebase APIs are called. If that condition isn't met, it will raise an exception explicitly telling you so.
In my code I call it in my main, which is the earliest place I can think if, and it works without problems:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
...
The initialization of Firebase at this level is pretty much instantaneous, as it's just waiting for the call to the native code to complete, and the native code itself does nothing more then look up the configuration values.
But if that is taking too long for you, you can call it without await. It just means that you may have to deal with that Future<FirebaseApp> later in your code where you access Firebase, typically by wrapping that in a FutureBuilder.

Related

Is there any need to use await when setting data in firestore from cloudfunctions

I have a web app that is running quite slow and has a few cloud functions used to update/set values in firestore
When I update a value in the firestore database, should I await the completion of the request, or can I trust that the request was sent and the data will be updated?
In other words, with the below function, does the await statement do anything to help with computation, or does it just increase the CPU time I'm using?
exports.exampleFunction = functions.https.onRequest(async (request, response)=> {
await db.collection('users').doc(request.body.userID).update({
username: request.body.username
})
response.send({done: true})
return ;
})
Thanks :)
You can refer to the Stackoverflow Answer where Doug has explained the consequences of removing await from the function.
You can also refer to the Documentation where the importance of managing the lifecycle of a function is explained.
When you return a JavaScript promise to a function, that function keeps running until the promise is resolved or rejected. To indicate that a function has
completed its work successfully, the promise should be resolved. To indicate an error, the promise should be rejected. This means you only need to handle
errors that you want to.

Can't create unit test with FireStore for flutterfire, throws during init, even with simplest possible test

// ignore_for_file: avoid_print
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('core tests - coffee', () {
test('fetch coffees', () async {
await Firebase.initializeApp();
final FirebaseFirestore firestore = FirebaseFirestore.instance;
print('initialized');
expect(firestore, isNotNull);
});
});
}
This is in a test. Oddly, it works in the live app, but not in a simple test case.
Errors during Firebase.initializeApp() with:
Null check operator used on a null value
MethodChannel.binaryMessenger
package:flutter/…/services/platform_channel.dart:121
I don't want a testWidgets. I don't want a mocked FireStore. I want to hit the real database.
I'm on a mac, running a simulator, using VSC, although the simulator shouldn't even be involved.
Firebase plugins wraps around native platform (firebase) SDKs and i think they are not available on when running tests.
I would suggest to use either the emulator suite or fake_cloud_firestore package, or do manual testing by humans (connected with a different firebase instance)

How to test a Flutter application using Firebase?

I am using Flutter and Firebase as my database. I want to do some unit test of my application, but when I start this test :
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Create the widget by telling the tester to build it.
await tester.pumpWidget(LoginPage());
expect(true, true);
});
I have the Exception :
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
But Firebase.initializeApp() is called in my main.dart here :
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
And I don't know how to initialize the Firebase app in my test.
Posting this as a community wiki as it's based on #GuilhermeGabanelli's comment.
If you check this flutterfire documentation on how to perform unit tests with Firebase Services you will see that:
The Firebase libraries need to run on an actual device or emulator. So if you want to run unit tests, you'll have to use Fakes instead. A Fake is a library that implements the API of a given Firebase library and simulates its behavior.
...
When initializing your app, instead of passing the actual instance of a Firebase library (e.g. FirebaseFirestore.instance if using Firestore), you pass an instance of a fake (e.g. FakeFirebaseFirestore()). Then the rest of your application will run as if it were talking to Firebase.
Followed by an example with sample code. I believe this is the cause of the issue you are facing and if you change your code to use Fakes this should be fixed.

How do the rest of the modules access "Firebase" class, after we initialize using ```Firebase.initializeApp();``` in the entry point?

So my app is working, but I want to understand what does the initialization actually do?
and why do we have access to a "Firebase" class only after we initialize?
in other words:
How do the rest of the modules access "Firebase" class, after we initialize using Firebase.initializeApp(); in the entry point?
for reference, this is one approach of how we initialize:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp()
);
}
My question is, how is the returned value of the initialized app stored? so that I can access it from any module?
In your case (no application name provided), it initializes a new FirebaseAppPlatform for the default Firebase App and returns it as a Future<FirebaseAppPlatform>. This method should be called before any usage of FlutterFire plugins.
Thanks to that FirebaseApp instance, all the Firebase module can get access to the initialized Firebase Application. Example for Firestore: FirebaseFirestore.instance
Thanks to that initialization using await, you'll also get a synchronous getter for the currentUser.

Nullreference exception does not show up when async Task discarded

I have an async Task with a method signature defined like this:
public async Task<bool> HandleFooAsync()
When executing this task in an async way and discarding the results, exceptions happening in this task do not show up in our logs.
_ = _slackResponseService.HandleFooAsync();
When I await the execution of the task I see the error in our logs
var result = await _slackResponseService.HandleFooAsync();
Is this expected behaviour? Is there a way to achieve a solution in between: "do not wait for the result, but log errors nevertheless.." ? We invested hours debugging our logging setup, just to learn that our logging setup is correct, but discard means in dotnet that everything is discarded - even logs. Which is a quite a new perspective for us, coming from a Python background.
Our logging setup follows the default logging setup for dotnet core 3 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1
Yes, it is an expected behavior. Call in that way can be considered like an anti-pattern. You can read about it C# Async Antipatterns
You need something which is called as "Fire and forget". One of its implementation can be find in repo AsyncAwaitBestPractices (nuget available too).
A Task in .net and netcore is meant to be awaited. If it is not awaited, the scope might be destroyed before the async method has finished.
If you want to run tasks in the background and not wait for a result you can use BackgroundService in .netcore or a third party such as Hangfire which supports fire and forget jobs out of the box
https://medium.com/#daniel.sagita/backgroundservice-for-a-long-running-work-3debe8f8d25b
https://www.hangfire.io/
One solution is to subscribe to the TaskScheduler.UnobservedTaskException event. It is not ideal because the event is raised when the faulted Task is garbage collected, which may happen long after the actual fault.
Another solution could be to use an extension method every time a task is fired and forgotten. Like this:
_slackResponseService.HandleFooAsync().FireAndForget();
Here is a basic implementation of the FireAndForget method:
public async static void FireAndForget(this Task task)
{
try
{
await task;
}
catch (Exception ex)
{
// log the exception here
}
}

Resources