'Flutter - how to get current context?

I am using Firebase cloud messaging for notifications, and i want to show a dialog or snackbar once i receive a notification when i am inside the application, my problem is that i am initializing the firebase configuration at the top of my widget tree (Splash screen once the app is starting)

_fireBaseMessaging.configure(
  onMessage: (Map<String, dynamic> message) async {
    dynamic data = message['data'];
    ................ // Adding a snackbar/alertdialog here doesn't work
  },
);

obviously if i set a dialog or snackbar it won't show since i need the context of my current page, is there any way to get the current context?

I also tried putting it inside the build widget of my splash screen but still the dialog isn't showing once i am on another page.

 @override
  Widget build(BuildContext context) {
    _fireBaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        dynamic data = message['data'];
        if (data['id'] == '1') {
          newPro = true;
        } else if (data['id'] == '2') {
          print("THIS WORKS!!!");
          showDialog(
              context: context,
              builder: (context) => AlertDialog(
                    content: ListTile(
                      title: Text("TEST"),
                      subtitle: Text("TEST"),
                    ),
                    actions: <Widget>[
                      FlatButton(
                        child: Text("OK"),
                        onPressed: () => Navigator.pop(context),
                      )
                    ],
                  ));
        }
      },
    );


Solution 1:[1]

I ended up using Overlay support:

https://pub.dev/packages/overlay_support

It is basically called at the very beginning of my tree just like wrapping providers at the main.dart, it worked like a charm, nothing else worked at all! Also here is a tutorial that helped me a lot:

https://medium.com/flutter-community/in-app-notifications-in-flutter-9c1e92ea10b3

Solution 2:[2]

I had the exact same issue, but I found a brilliant thread on GitHub. Basically, you can create a navigatorKey and pass that in to MaterialApp, and then use that navigatorKey to change route.

See how in this thread: https://github.com/brianegan/flutter_redux/issues/5#issuecomment-361215074

Solution 3:[3]

Because it makes me uncomfortable to have the answer embedded in a link, here is the answer (credit to xqwzts on Github).

Use a GlobalKey you can access from anywhere to navigate:

Create the key:

final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();

Pass it to your App:

new MaterialApp(
      title: 'MyApp',
      onGenerateRoute: generateRoute,
      navigatorKey: navigatorKey,
    );

Push routes:

navigatorKey.currentState.pushNamed('/someRoute');

Solution 4:[4]

An elegant solution to this problem is to use GlobalKey. That'll let you find the current BuildContext and do things with it.

You make a file called eg. global.dart looking like this:

import 'package:flutter/material.dart';

class GlobalVariable {
  static final GlobalKey<NavigatorState> navState = GlobalKey<NavigatorState>();
}

You use this in your main() and MaterialApp() like this:

import 'global.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'fcm.dart';  // My Firebase Cloud Messaging code
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'screens/welcome_screen.dart';


void main() {
  print('Running main()');
  WidgetsFlutterBinding.ensureInitialized();
  Firebase.initializeApp();
  initializeFcm('', GlobalVariable.navState); // Sending the global key when initializing Firebase Cloud Messaging
  FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);

  runApp(MyApp());
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WelcomeScreen(),
      navigatorKey: GlobalVariable.navState,  // Putting the global key in the MaterialApp
    );
  }
}

Then, in the file that handles Firebase Cloud Messaging, which I've named fcm.dart, you'll be able to use the GlobalKey to find the current context and use it, for example like this:

import 'package:blackbox/global.dart';
import 'online_screens/game_hub_screen.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

void initializeFcm(String token, GlobalKey myGlobalKey) async {
  print('Initializing Firebase Cloud Messaging...');
  await Firebase.initializeApp();

  FirebaseMessaging.onMessageOpenedApp.listen((remoteMsg) {
    // Using the currentContext found with GlobalKey:
    Navigator.push(GlobalVariable.navState.currentContext, MaterialPageRoute(builder: (context) {
      return GameHubScreen();
    }));
  });
}

Solution 5:[5]

do the initializing inside a build method of your first widget in the tree ! which normally it called an App widget and it is StateLess StateFull widget and inside the build method you have access to the BuildContext

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bahij.Mik
Solution 2 Tommy Østgaard
Solution 3 tonymontana
Solution 4 Karolina Hagegård
Solution 5 Amir Hossein Mirzaei