jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.18k stars 1.6k forks source link

You are trying to use contextless navigation without a GetMaterialApp or Get.key. #1086

Open jenniestrongbow opened 3 years ago

jenniestrongbow commented 3 years ago

ATTENTION: DO NOT USE THIS FIELD TO ASK SUPPORT QUESTIONS. USE THE PLATFORM CHANNELS FOR THIS. THIS SPACE IS DEDICATED ONLY FOR BUGS DESCRIPTION. Fill in the template. Issues that do not respect the model will be closed.

Describe the bug When I

**Reproduction code

GetMaterialApp(                    
    home: SplashScreen(),
  ));

Then when I call the following top-level function (not inside a class), I get the error below.

Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
  Get.to(() => BlankScreen(payload: message));
});

I get the following error:

You are trying to use contextless navigation without a GetMaterialApp or Get.key

To Reproduce Explained above. Thanks

Expected behavior It should open my BlankScreen widget.

Flutter Version: 1.22.6

Getx Version: ^3.25.4

Describe on which device you found the bug: Samsung Note 3

Thanks!

jonataslaw commented 3 years ago

Problem: when navigation is called, Flutter is not yet ready to navigate (you are probably receiving a native code call, which is received before Flutter even rendered the first screen). Solution: Send the navigation only when Flutter is ready, that is, when he renders the first frame.

Something like that:

Future myBackgroundMessageHandler(Map<String, dynamic> message) async { SchedulerBinding.instance.addPostFrameCallback((_) => Get.to(() => BlankScreen(payload: message))); });

jenniestrongbow commented 3 years ago

Hi, thanks for your quick reply.

Actually the myBackgroundMessageHandler function is called when the app is in the background and it receives a FCM notification.

I tried your solution, and it delayed the same error message.

This is driving me crazy. What I really want to do is open a widget when the app is in the background (after a Google FCM has been received).

I added GetMaterialApp and only used GetX to navigate.

Here is the error I get:

════════ Exception caught by scheduler library ═════════════════════════════════ The following message was thrown during a scheduler callback: You are trying to use contextless navigation without a GetMaterialApp or Get.key. If you are testing your app, you can use: [Get.testMode = true], or if you are running your app on a physical device or emulator, you must exchange your [MaterialApp] for a [GetMaterialApp].

jonataslaw commented 3 years ago

Try change ()=> to (){} to prevent dart typo inference,

Future myBackgroundMessageHandler(Map<String, dynamic> message) async {
  SchedulerBinding.instance.addPostFrameCallback((_) {
    Get.to(() => BlankScreen(payload: message));
  });
}

If it doesn't work out, you may have to take some more hardcore action, like using a Future.delayed.

Future myBackgroundMessageHandler(Map<String, dynamic> message) async {
    Future.delayed(Duration(milliseconds: 200), () {
      Get.to(() => BlankScreen(payload: message));
    });
}

One of these two should work. This error is not related to the library, but only to the time you are calling the route (before the flutter builds the runApp).

jenniestrongbow commented 3 years ago

Thank you. Unfortunately, none of the two pieces of code work.

I believe that the issue is totally related to Get. I want to show a widget when the app is in the background from a top-level function that has no context. All my other Get.to calls work in the app, except in the myBackgroundMessageHandler above. This function is called when an FCM notification is received when the app is in the background.

Thanks

jonataslaw commented 3 years ago

Well, I just tested it and both modes work with background notifications from firebase. Update GetX, and try the solution after a clean flutter. As explained above, this is not a GetX error, you need the Flutter engine to be attached and the runApp to be active to use Flutter navigation, otherwise you will be able to display at most the activitys / views of the native layer. There is no way for GetX to work without Flutter. In addition, the code provided works without problems. If you think this is an error, please provide a code or repository for reproducing the problem, or the issue will be closed.

jenniestrongbow commented 3 years ago

Thanks for your quick reply again. I am using the latest version of GetX. I'll try to clean Flutter and see if it makes a difference. My Flutter environment is perfectly setup and the Get.to work perfectly everywhere except in top-level functions (without context). This is such a strange problem. I just want to be able to display a widget when a FCM notification is received while my app is in the background. I'll report back to you asap. Thanks

jenniestrongbow commented 3 years ago

I give up. Still not working. Get.to does not work in functions that are outside of classes. Thanks anyway.

fer-ri commented 3 years ago

Actually the myBackgroundMessageHandler function is called when the app is in the background and it receives a FCM notification.

When the app is in the background, it should be received via onResume or onMessage right?

image

fer-ri commented 3 years ago

I think you are misunderstood about how FCM works.

You will get this error

You are trying to use contextless navigation without GetMaterialApp or Get.key.

When you are trying to send data only instead of notification to bring back the app from the background/terminated state.

To achieve this, you need to use the notification type of FCM, and put handler for onLaunch and onResume

jenniestrongbow commented 3 years ago

@ghprod, what I'm trying to do is display a widget (using GetX) when a notification is received while the app is in the background (without a user clicking a notification). What you're showing me is how to handle clicks when a notification is received. Thanks anyway.

fer-ri commented 3 years ago

Based on the doc, you should use onMessage handler. Or I missed something?

And since onMessage handler not located on top level function, then we can use Get.to() freely