I am trying to achieve open specific screen on clicking push notification and my payload looks like this:
var payload = {
notification: {
Initially, @xqwzts answer not working for me. After a lot of research, I find that We need to initialize the configure method little delay. I attached the code below. It will helpful for others.
void initState() {
// TODO: implement initState
super.initState();
_firebaseMsgListener();
}
void _firebaseMsgListener() {
// if (Platform.isIOS) iOS_Permission();
_firebaseMessaging.getToken().then((token) {
Fimber.d("=====> token : $token");
UpdateTokenRequest request = UpdateTokenRequest();
request.token = token;
homeBloc.updateFCMToken(request);
});
Future.delayed(Duration(seconds: 1), () {
_firebaseMessaging.configure(
onBackgroundMessage: myBackgroundMessageHandler,
onMessage: (Map<String, dynamic> message) async {
Fimber.d("=====>on message $message");
Fluttertoast.showToast(msg: "onMessage $message");
},
onResume: (Map<String, dynamic> message) async {
Fimber.d("=====>onResume $message");
Fluttertoast.showToast(msg: "onResume $message");
},
onLaunch: (Map<String, dynamic> message) async {
Fimber.d("=====>onLaunch $message");
Fluttertoast.showToast(msg: "onLaunch $message");
},
);
});
}
Future<dynamic> myBackgroundMessageHandler(
Map<String, dynamic> message) async {
print("_backgroundMessageHandler");
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
print("_backgroundMessageHandler data: ${data}");
}
if (message.containsKey('notification')) {
// Handle notification message
final dynamic notification = message['notification'];
print("_backgroundMessageHandler notification: ${notification}");
Fimber.d("=====>myBackgroundMessageHandler $message");
}
return Future<void>.value();
}
As @xqwzts method works well for receiving messages on App is an open state,
the following example will navigate to a specific page,
[THE CODE IS TAKEN FROM THE FIREBASE MESSAGING PLUGIN EXAMPLE CODE ONLY AND IT NAVIGATES TO A NAMED PAGE, IN WHICH THE DATA WE SENT VIA FIREBASE CONSOLE]
//eg: if you give /Nexpage3 in the status field then it will navigate to Nextpage3 of your App
UNDERSTAND THE 2 THINGS,FCM NOTIFICATIONS HAS 2 SECTIONS
1st Message Title Section in your firebase cloud messaging page is called Notification Data[when the App is minimized or closed it will be shown as a notification]
2nd Message Title section which is in the bottom of the webpage is called Message Data, [it will be shown In inside app as a notification or an Alert dialogue that's up to your wish]
STEPS Create a dummy Project then use firebase message plugin, and in that Box give BMW Cars as atopic and click subscribe
Now go to your console then send a message with the FOLLOWING FORMAT it must contain Id
and Status
keys because we are parsing the Id and Status Keys in order to show NextPage with the Status Key's Value but if u prefer a field like title or body then u can do that too but make sure to parse the map value in ur flutter code.
//THIS IS A LITTLE BIT MODIFIED VERSION OF Example Code given in Firebase
//Messaging Plugin
//WHEN U PASTE THE CODE IN UR VS CODE OR ANDROID STUDIO PLEASE Format the
//Document because it is aligned in single lines
import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
new MaterialApp(
home: new PushMessagingExample(),
routes: <String,WidgetBuilder>{
"/Nexpage1":(BuildContext context)=> new Nexpage1(),
"/Nexpage2":(BuildContext context)=> new Nexpage2(),
"/Nexpage3":(BuildContext context)=> new Nexpage3(),
} ),);}
//INITIAL PARAMETERS
String _homeScreenText = "Waiting for token...";
bool _topicButtonsDisabled = false;
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
final TextEditingController _topicController = new TextEditingController(text: 'topic');
final Map<String, Item> _items = <String, Item>{};
Item _itemForMessage(Map<String, dynamic> message) {
final String itemId = message['id'];
final Item item = _items.putIfAbsent(itemId, () => new Item(itemId: itemId))..status = message['status'];
return item;
}
//MAIN CLASS WHICH IS THE HOMEPAGE
class PushMessagingExample extends StatefulWidget {
@override
_PushMessagingExampleState createState() => new _PushMessagingExampleState();
}
class _PushMessagingExampleState extends State<PushMessagingExample> {
void _navigateToItemDetail(Map<String, dynamic> message) {
final String pagechooser= message['status'];
Navigator.pushNamed(context, pagechooser);
}
//CLEAR TOPIC
void _clearTopicText() {setState(() {_topicController.text = "";_topicButtonsDisabled = true;});}
//DIALOGUE
void _showItemDialog(Map<String, dynamic> message) {showDialog<bool>(context: context,builder: (_) => _buildDialog(context, _itemForMessage(message)),).then((bool shouldNavigate) {if (shouldNavigate == true) {_navigateToItemDetail(message);}});}
//WIDGET WHICH IS GOING TO BE CALLED IN THE ABOVE DIALOGUE
Widget _buildDialog(BuildContext context, Item item) {return new AlertDialog(content: new Text("Item ${item.itemId} has been updated"),actions: <Widget>[new FlatButton(child: const Text('CLOSE'),onPressed: () {Navigator.pop(context, false);},),new FlatButton(child: const Text('SHOW'),onPressed: () {Navigator.pop(context, true);},),]);}
@override
void initState() {
super.initState();
_firebaseMessaging.configure(
onLaunch: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onResume: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onMessage: (Map<String, dynamic> message) async {_showItemDialog(message);},);
//GETTING TOKEN FOR TESTING MANUALY
_firebaseMessaging.getToken().then((String token) {assert(token != null);setState(() {_homeScreenText = "Push Messaging token: $token";});print(_homeScreenText);});}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: const Text('Push Messaging Demo'),),
body: new Material(
child: new Column(
children: <Widget>[
new Center(
child: new Text(_homeScreenText),
),
new Row(children: <Widget>[
new Expanded(
child: new TextField(
controller: _topicController,
onChanged: (String v) {
setState(() {
_topicButtonsDisabled = v.isEmpty;
});
}),
),
new FlatButton(
child: const Text("subscribe"),
onPressed: _topicButtonsDisabled
? null
: () {
_firebaseMessaging
.subscribeToTopic(_topicController.text);
_clearTopicText();
},
),
new FlatButton(child: const Text("unsubscribe"),
onPressed: _topicButtonsDisabled? null: () { _firebaseMessaging.unsubscribeFromTopic(_topicController.text);
_clearTopicText();},),
])],),));}}
//THREE DUMMY CLASSES FOR TESTING PURPOSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PAGE1
class Nexpage1 extends StatefulWidget { @override _Nexpage1State createState() => _Nexpage1State();}
class _Nexpage1State extends State<Nexpage1> { @override Widget build(BuildContext context) { return Scaffold(body: new Center(child: new Text(" Page1"),));}}
//PAGE2
class Nexpage2 extends StatefulWidget { @override _Nexpage2State createState() => _Nexpage2State();}
class _Nexpage2State extends State<Nexpage2> { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: new Text("2pending"),) ); }}
//PAGE3
class Nexpage3 extends StatefulWidget { @override _Nexpage3State createState() => _Nexpage3State();}
class _Nexpage3State extends State<Nexpage3> { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: new Text("3connected"),) ); }}
//THIS IS THE CLASS WHICH IS USED TO PARSE THE INFORMATION
class Item {
Item({this.itemId});
final String itemId;
StreamController<Item> _controller = new StreamController<Item>.broadcast();
Stream<Item> get onChanged => _controller.stream;
String _status;
String get status => _status;
set status(String value) {
_status = value;
_controller.add(this);
}
static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
Route<Null> get route {
final String routeName = '/detail/$itemId';
return routes.putIfAbsent(
routeName,
() => new MaterialPageRoute<Null>(
settings: new RouteSettings(name: routeName),
builder: (BuildContext context) => new Nexpage3(),
),
);
}
}
onBackgroundMessage: myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
await print("onLaunch: $message");
///_navigateToItemDetail(message);
await _showItemDialog(message); // Diyalog Kutusu Oluştur
},
onResume: (Map<String, dynamic> message) async {
await print("onResume: $message");
///_navigateToItemDetail(message);
await _showItemDialog(message); // Diyalog Kutusu Oluştur
},
Add await is working
A few things here:
1- click_action
has to be set to "FLUTTER_NOTIFICATION_CLICK"
2- click_action
has to be set in the data
section of a payload
DATA='{
"notification": {
"body": "this is a body",
"title": "this is a title"
"click_action": "FLUTTER_NOTIFICATION_CLICK",
},
"data": {
"sound": "default",
"status": "done",
"screen": "screenA",
},
"to": "<FCM TOKEN>"
}'
This should allow you to receive the message in the onMessage
handler in your flutter app.
From there you can call Navigator.of(context).pushNamed(message['screen'])
.
If you don't have a BuildContext
at that point, you can register a GlobalKey
as the navigatorKey
property of your MaterialApp
, and use it to access your Navigator
globally, via GlobalKey.currentState
Step 1: pass one key-value pair in the firebase notification as click_action
: FLUTTER_CLICK_ACTION
.
Step 2: Using step 1 you'll receive the onTap callback of notification inside onResume
or onLaunch
method.
Step 3: Perform the following scenario for navigating to a specific screen on click of notification.
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
@override
Widget build(BuildContext context) {
return new MaterialApp(
navigatorKey: navigatorKey,
home: new Scaffold(
appBar: AppBar(),
body: new Container(),
),
);
}
}
onResume
or onLuanch
method navigate to your screen using below line of code: navigatorKey.currentState.push(
MaterialPageRoute(builder: (_) => Dashboard())
);
onLaunch: (Map<String, dynamic> message) {
print("I am here onLaunch");
print(message);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScreenA()
)
);
},
onResume: (Map<String, dynamic> message) {
print("I am here onResume");
print(message);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScreenA()
)
);
},
try this