Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: local notification plugin, navigate to specific screen when the user tap the notification

I`m using local notification plugin and everything works fine except that when i tap on the notification.i want to navigate to specific screen when the user tap the notification

Future onSelectNotification(String payload) async {
    //convert payload json to notification model object
    try{
    Map notificationModelMap = jsonDecode(payload);
    NotificationModel model = NotificationModel.fromJson(notificationModelMap);

    await Navigator.push(
        context,// it`s null!
        new MaterialPageRoute(
            builder: (context) => CommitmentPage(model)));}
            catch(e){print(e.toString());}
  }

but the context always null and gives me an exception NoSuchMethodError: The method 'ancestorStateOfType' was called on null.

Edit

i tried to use navigatorKey and pass it to material app as suggested by @Günter Zöchbauer but it gives me another exception

Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget

main.dart

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      navigatorKey:navigatorKey ,
      title: 'notification',
      theme: ThemeData(
        primarySwatch: Colors.purple,
      ),
      home: new RootPage(auth: new Auth(),),
    );
  }

}

ReminderPage

   class ReminderPage extends StatefulWidget {

    @override
      _ReminderPageState createState() => _ReminderPageState();

    }

class _ReminderPageState extends State<ReminderPage> {
  final flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
....

 @override
  void initState() {
    super.initState();

    _initLocalNotification();
....

  }


// this method is called when u tap on the notification
 Future onSelectNotification(String payload) async {

    //convert payload json to notification model object
    Map notificationModelMap = jsonDecode(payload);
    NotificationModel model = NotificationModel.fromJson(notificationModelMap);

    try{
   await Navigator.push(
        MyApp.navigatorKey.currentState.context,
        new MaterialPageRoute(
            builder: (context) => CommitmentPage(model)));}
            catch(e){print(e.toString());}


  }

}

Edit 2 instead of using

 await Navigator.push(
            MyApp.navigatorKey.currentState.context,
            new MaterialPageRoute(
                builder: (context) => CommitmentPage(model)));}
                catch(e){print(e.toString());}

i used

await  MyApp.navigatorKey.currentState.push(MaterialPageRoute(builder: (context) => CommitmentPage(model)));

and it worked fine, but when i tap on the notification after killing the app, it takes me to the home page not to the desired one! i think navigatorKey has not been initialized yet!

like image 596
M.Ali Avatar asked Jan 10 '19 21:01

M.Ali


2 Answers

1. FMC payload

{
  "notification": {
    "body": "Hey, someone book your product", 
    "title": "production booking"
  }, 
  "priority" : "high",
  "data": {
    "action" : "BOOKING" //to identify the action
  },
  "to": "deviceFCMId"
}

2. Set the payload data in localnotification.show method

showNotification(RemoteMessage message) {
  RemoteNotification notification = message.notification;
  AndroidNotification android = message.notification?.android;
  String action = message.data['action']; // get the value set in action key from FCM Json in Step1
  // local notification to show to users using the created channel.
  if (notification != null && android != null) {
    flutterLocalNotificationsPlugin.show(
        notification.hashCode,
        notification.title,
        notification.body,
        NotificationDetails(
            android: androidNotificationDetails, iOS: iOSNotificationDetails),
        payload: action // set the value of payload
    );
  }
}

3. Create a navigatorKey in MyApp class

class _MyAppState extends State<MyApp> {
  final GlobalKey<NavigatorState> navigatorKey =
      GlobalKey(debugLabel: "Main Navigator"); //
}

4. Set navigatorkey on your MaterialApp

@override
  Widget build(BuildContext context) {
    //this change the status bar color to white
    return MaterialApp(
          navigatorKey: navigatorKey,
    ....

5. on initState, init localnotificationPlugin and declare the onSelectNotification method

@override
  void initState() {
    super.initState();
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);
  }

  Future<dynamic> onSelectNotification(payload) async {
  // implement the navigation logic
  }

6. Navigation logic example

Future<dynamic> onSelectNotification(payload) async {
// navigate to booking screen if the payload equal BOOKING
if(payload == "BOOKING"){
 this.navigatorKey.currentState.pushAndRemoveUntil(
  MaterialPageRoute(builder: (context) => BookingScreen()),
   (Route<dynamic> route) => false,
   );
 }
}
like image 63
Nehemie KOFFI Avatar answered Sep 23 '22 17:09

Nehemie KOFFI


Pass a navigatorKey to MaterialApp and use this key to get the context. This context contains a Navigator and you can use it to switch to whatever page you want.

https://docs.flutter.io/flutter/material/MaterialApp/navigatorKey.html

like image 28
Günter Zöchbauer Avatar answered Sep 23 '22 17:09

Günter Zöchbauer