FirebaseAuth.instance.userChanges keeps getting called - flutter

In main.dart I've added this:
FirebaseAuth.instance.userChanges().listen((event) async {
debugPrint('user state changed in main');
});
The event is continuously getting triggered, with no changes to the users logged in status (I am developing for the web, not tested on devices).

Use authStateChanges when interested in the current user.
authStateChanges
Notifies about changes to the user's sign-in state (such as sign-in or sign-out).
userChanges
Notifies about changes to any user updates.

The issue was isolated - I was calling this inside the .listen((event) async {}
token = await FirebaseAuth.instance.currentUser!.getIdTokenResult(true);
which was triggering the event again...

Related

Flutter integration test, how to ensure user is signed out? (flushed state)

I'm writing my first Flutter integrations tests, and noticed that when the app starts up, the user is already signed in and lands on the page after sign in. I don't know why this happens, maybe because the app has been running previously on the same device in development mode with a signed in user?
Is there a way to start the tests with no previous state, no sessions, etc? I can't find anything in the documentation for this.
Use setUp and tearDown to set/clear state before/after each test.
setUp(() async {
// TODO
});
tearDown(() async {
// TODO
});

How to wait for a Flutter app to open before navigating to a particular page by clicking a scheduled notification?

I'm working on a Flutter project where I had to set a scheduled local notification that would fire everyday at 10 am. And, the user should be taken to a certain page of the app upon clicking the notification.
I've completed this part and the functionality works fine when the app is open and the user clicks on the notification.
But the problem arises when the app is closed and the notification is fired and the user clicks on the notification. It doesn't take the user to that certain page. I tried to modify the click handling function by making it an async function. But it doesn't work accordingly.
Can someone suggest me what to do now?
Create a notification handler.
Initialize your notification channel with high importance
Just before your app runs, before runApp(yourApp), create call a foregroundMessageHandler that you have initialized before the void main(){}
the foregroundMessageHandler should be a *TopMost initialization.
in the foregroundMessageHandler function, define the navigation behaviour
I don't know which library you are using for local notifcations. but if you are using flutter_local_notifications library check the link: https://pub.dev/packages/flutter_local_notifications
, you can check the data recived in selectNotification method and redirect the user to required page
void selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
await Navigator.push(
context,
MaterialPageRoute<void>(builder: (context) => SecondScreen(payload)),
);
}
other libraries should have same functionality.

Flutter Firebase Anonymous Authentification Sign-In Upon Opening

I currently have an app which Sign's-In a User when a button is tapped by calling :
Future<void> anonymousSignIn(DocumentSnapshot<Object> document, context) async {
await FirebaseAuth.instance.signInAnonymously();
var user = await FirebaseAuth.instance.currentUser;
var uid = user.uid;
ScaffoldMessenger.of(context).showSnackBar(getSnackBar("Signed In"));
}
But I'd like the User to not have to press any button & instead be automatically Signed-In Anonymously when the App is Open - I'm not sure where to write that & how in my App
Also I ultimately will want to allow the user to also Sign-In with e-mail or Google so before Sign-In Anonymously upon Opening it will have to check if the user was not already Signed-In with those methods
🙏
You can do that by await FirebaseAuth.instance.signInAnonymously() it in your main() function before runApp(), so now you will have a user logged when the app starts.
I don't think your second part makes a sense, you will either automatically sign in the user anonymously or give him the options you mentioned which require the click to trigger Google oAuth flow or pass his credentials for the mail login.
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseAuth.instance.signInAnonymously();
var user = await FirebaseAuth.instance.currentUser;
var uid = user.uid;
runApp(child : App());
}
This is the full solution I ended up writing thanks to #esentis
but I'm still wondering - how to check if user had not logged In with Google the last time it open the App
to log it in with Google Automatically without pressing button instead of Anonymously
esentis suggested using Shared Preferences to store the last login State - I will try to post my code when I have implemented it

Why is onTokenRefresh not firing?

I'm new to firebase messaging and flutter. According to the flutter firebase_messaging package docs, onTokenRefresh is fired when a new FCM token is generated. And according to Google's firebase docs there are two scenarios that triggers token generation:
When a new token is generated on initial app startup
Whenever an existing token is changed
Here is a simplified version of the main function of my application. After each execution, I delete the app from the emulator and the displayed token does indeed change. Despite this, onTokenRefresh is never fired and it should if my understanding of the documentation is correct.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
print("New token: $token");
});
String token = await FirebaseMessaging.instance.getToken();
print("Token: $token");
//runApp(MyApp());
}
As I said, I'm new to flutter, dart and firebase messaging, is there something I'm fundamentally misunderstanding? Thanks.
So I think I figured it out. I noticed that sometimes, the onTokenRefresh does indeed fire. And I was wondering if it had something to do with how the flutter application is launched onto the emulator, in the sense that there is a race condition between when the token is generated and the listener attached.
To get the app to appear to start for the first time, I wiped the app data. Unfortunately this causes the flutter to automatically disconnect from the app which means I won't see the output of the print statement. So instead of trying to print when the token generation occurs, I assigned a value from the onTokenRefresh listener to a variable. I then updated a text widget with the value of the variable. And onTokenRefresh does indeed fire each time at start up if the app data has previously been wiped.

FCM: How to bring the app from background to foreground?

I have an app in which I am using FCM (Firebase Cloud Messaging).
As given in the README, I've managed to get it all working and the event handlers for onResume, onMessage, onLaunch are all firing properly.
The onBackgroundMessage which I think is supposed to run whenever the notifications appear while the app is inactive, needs a top-level dart function.
I need this function to render a particular widget, say, IncomingCall. But this being a top-level function, the best I could think of, is to invoke the main():
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
main();
}
which then calls runApp(IncomingCall()) but even this is not working.
So how does one render a widget in Dart when the app is inactive?