Reputation: 10235
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!
Upvotes: 19
Views: 21244
Reputation: 657376
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://api.flutter.dev/flutter/material/MaterialApp/navigatorKey.html
Upvotes: 4
Reputation: 1395
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,
);
}
}
Upvotes: 16
Reputation: 56
With the latest change you've done, you being taken to the home page, is more to do with the fact that you instantiate and initialise the plugin a couple of pages further in your app. considering the app got killed, the plugin would've been killed too. you should look into initialising the plugin closer to when your app starts e.g. around when the app is created or when the first page is created, depending on the behaviour you want. In this issue https://github.com/MaikuB/flutter_local_notifications/issues/99, another dev has been able to change the first page shown if the app is killed but that may different to what you want to happen.
Upvotes: 3