flutter - How to do a task after user open push notif message (FCM)
Sure, you can do it on Flutter too.
First, I expect you set these codes in your manifest
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
In your notification body in JSON in the backend (node.js) add tag element.
const payload: admin.messaging.MessagingPayload = {
notification: {
title: 'New Puppy!',
body: `${puppy.name} is ready for adoption`,
icon: 'your-icon-url',
tag: 'puppy',
data: {"click_action": "FLUTTER_NOTIFICATION_CLICK", "id": "1", "status": "done"},
click_action: 'FLUTTER_NOTIFICATION_CLICK' // required only for onResume or onLaunch callbacks
}
};
And in Dart code, make sure to set this code in the first initState() page.
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
var tag = message['notification']['title']);
if (tag == 'puppy')
{
// go to puppy page
} else if (tag == 'catty')
{
// go to catty page
}
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
// TODO optional
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
// TODO optional
},
);
The most of my answer is from this blog.
It mentioned in the blog when the callbacks fires, so decide closely which one set your code in.
onMessage fires when the app is open and running in the foreground.
onResume fires if the app is closed, but still running in the background.
onLaunch fires if the app is fully terminated.
Update
as your question has been updated, please consider the following from this article
• Notification Messages - Consist of a title and a message body and trigger the notification system on arrival at the device. In other words, an icon will appear in the status bar and an entry will appear in the notification shade. Such notifications should be used when sending an informational message that you want the user to see.
ex:
var payload = { notification: { title: "Account Deposit", body: "A deposit to your savings account has just cleared." } };
• Data Messages - Contain data in the form of key/value pairs and are delivered directly to the app without triggering the notification system. Data messages are used when sending data silently to the app.
ex:
var payload = { data: { account: "Savings", balance: "$3020.25" } };
• Combined Messages – Contain a payload comprising both notification and data. The notification is shown to the user and the data is delivered to the app.
ex:
var payload = { notification: { title: "Account Deposit", body: "A deposit to your savings account has just cleared." }, data: { account: "Savings", balance: "$3020.25" } };
So, I think you will use the third one, which sending notification and data in the same time.
You can simply access the data using dart as below.
message['data']['account']
Update 2
As you updated your question and my solution didn't work with you in a good manner. I decided to test it myself, and guess what ! It works fine with your and same codes.
My node.js backend code
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
const fcm = admin.messaging();
exports.sendNotification = functions.firestore
.document('orders/{orderId}')
.onCreate(async snapshot => {
const order = snapshot.data();
// Token of my device only
const tokens = ["f5zebdRcsgg:APA91bGolg9-FiLlCd7I0LntNo1_7b3CS5EAJBINZqIpaz0LVZtLeGCvoYvfjQDhW0Qdt99jHHS5r5mXL5Up0kBt2M7rDmXQEqVl_gIpSQphbaL2NhULVv3ZkPXAY-oxX5ooJZ40TQ2-"];
const payload = {
notification: {
title: "Account Deposit",
body: "A deposit to your savings account has just cleared."
},
data: {
account: "Savings",
balance: "$3020.25",
link: "https://somelink.com"
}
};
return fcm.sendToDevice(tokens, payload);
});
and dart code
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
@override
void initState() {
super.initState();
_firebaseMessaging.requestNotificationPermissions();
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
var data2 = message['data']['link'];
print ("===>data_notif2 = "+data2.toString());
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
// TODO optional
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
// TODO optional
},
);
_saveDeviceToken();
}
/// Get the token, save it to the database for current user
_saveDeviceToken() async {
// Get the current user
String uid = 'jeffd23';
// FirebaseUser user = await _auth.currentUser();
// Get the token for this device
String fcmToken = await _firebaseMessaging.getToken();
// Save it to Firestore
if (fcmToken != null) {
print(fcmToken);
}
}
and the console output
I/flutter (20959): onMessage: {notification: {title: Account Deposit, body: A deposit to your savings account has just cleared.}, data: {account: Savings, balance: $3020.25, link: https://somelink.com}}
I/flutter (20959): ===>data_notif2 = https://somelink.com
So I believe the problem is somehow in your codes, not in the solution I give to you. Please clearly look for the problem you may have. Hope you find it and work well for you.
Yes it is possible in native but I'm not sure in flutter. You can build a PendingIntent with a back stack.
Intent notifIntent = new Intent(this, notifActivity.class);
TaskStackBuilder stkBuilder = TaskStackBuilder.create(this);
stkBuilder.addNextIntentWithParentStack(notifIntent);
PendingIntent resultPendingIntent =
stkBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Then you should pass the PendingIntent to the notification.
check this link: https://developer.android.com/training/notify-user/navigation