How to do firebase push notification with redirect with payload data in flutter.? - flutter

Here is my code below :-
var typeId = message!=null?message.data["payload"]:payload;
if(typeId["type"]=="XYZ"){
//Navigate to a screen
}else{}
this is not working and throwing exception.

Your exception is because of you've not decoded your message.data["payload"].
Because Data payload contains custom key-value pairs not a JSON format. you have to decode it.
here is your solution:
var typeId = message!=null ? json.decode(message.data["payload"]) : payload;
if(typeId["type"]=="XYZ"){
//Navigate to a screen
}
else{
}
happy coding...

Set up Firebase Cloud Messaging (FCM) in your Flutter project by adding the firebase_messaging package to your pubspec.yaml file and configuring your Firebase project.
In your main.dart file, add the following code to set up a Firebase Cloud Messaging listener:
FirebaseMessaging.instance.getToken().then((token) {
print('Token: $token');
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Message data: ${message.data}');
print('Message notification: ${message.notification}');
// handle your notification here
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('Message data: ${message.data}');
// handle your notification here
});
3.n the onMessage and onMessageOpenedApp listeners, you can handle the received notification data and show a notification to the user using the flutter_local_notifications package. You can also use the Navigator class to navigate to a specific screen in your app.
For example, you can use the following code to show a notification with a payload data and redirect the user to a specific screen when the notification is clicked:
Future<void> showNotification(RemoteMessage message) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'your channel id',
'your channel name',
'your channel description',
importance: Importance.max,
priority: Priority.high,
showWhen: false,
);
var platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
message.notification?.title,
message.notification?.body,
platformChannelSpecifics,
payload: message.data['screen'],
);
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Message data: ${message.data}');
print('Message notification: ${message.notification}');
showNotification(message);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('Message data: ${message.data}');
String screen = message.data['screen'];
if (screen != null) {
Navigator.pushNamed(context, screen);
}
});
In the code above, the showNotification function is called to show a notification with the title and body of the received message. The payload parameter is used to pass the screen name to navigate to when the user clicks the notification.
When the notification is clicked, the onMessageOpenedApp listener is triggered, and the screen value is extracted from the message data. If the screen value is not null, the Navigator class is used to navigate to the specified screen.
Make sure to handle any errors that may occur while implementing push notifications and follow the guidelines provided by the Firebase documentation for secure and reliable push notifications.

Related

Why FCM not working on android device in flutter application?

I currently create a chat application and I try to implement the notification system when an user receive a new incoming message.
It's work perfectly on iOS devices, but not work on android device.
Thanks for your help,
I tried to request a notification permission to a user. But on android device I didn't have any pop up spawn on the screen. I added firebasemessaging.onmessage.listen to try to fix the bug, but it did not work.
import 'package:firebase_messaging/firebase_messaging.dart';
class PermissionService {
Future<void> notification() async {
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
FirebaseMessaging.onMessage.listen((event) {
print("A new message event was published");
});
FirebaseMessaging.onMessageOpenedApp.listen((event) {
print("A new OpenedAppMessage event was published");
});
}
}
That is my get fcm token function. The goal of the method is get a fcm token of the device. This function work perfectly, because I can see the fcm token of the android device inside my database.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
class FCMService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Future<void> createFcmToken() async {
final User? user = _firebaseAuth.currentUser;
final fcmToken = await FirebaseMessaging.instance.getToken();
if (user != null) {
await FirebaseFirestore.instance
.collection("fcm_token")
.doc(user.uid)
.set({
"fcm_token": fcmToken,
"user_id": user.uid,
});
}
}
}
On this image, I can see the cloud function start, and send the notification with fcm token
firebase cloud function
when app running on foreground, FCM android didnt popup notification. it already mentioned on the documentation https://firebase.flutter.dev/docs/messaging/notifications#android-configuration
thats why, we need another additional plugin to handle foreground notification on Android. there are many option plugin in pub.dev , but they recommend to use
flutter_local_notifications package
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
// If `onMessage` is triggered with a notification, construct our own
// 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(
channel.id,
channel.name,
channel.description,
icon: android?.smallIcon,
// other properties...
),
));
}
});
please read the documentation for detail setup

Flutter - Endless notification on a single pusher beams event

Describe the bug
I am using pusher beams to fire event from server and I use flutter local notification to show the notification when the event is received by app.
Sample code to reproduce the problem
I have called initPusherBeams() in my init state (please read to the end I am quite sure this issues is with flutter local notifications)
#override
void initState() {
super.initState();
_setAuthData().then((_) {
if (_user?.id != null) initPusherBeams();
});
// notification related
_notiInit();
_requestPermissions();
_configureDidReceiveLocalNotificationSubject();
_configureSelectNotificationSubject();
// ask for app rating
WidgetsBinding.instance.addPostFrameCallback((_) => _ratingDialog());
}
and then, ininitPusherBeams function, I have
initPusherBeams() async {
// Let's see our current interests
await PusherBeams.instance.setDeviceInterests([
// 'App.Models.User.${_user!.id}',
'debug-new'
]);
// This is not intented to use in web
if (!kIsWeb) {
await PusherBeams.instance.onMessageReceivedInTheForeground(_onMessageReceivedInTheForeground);
}
}
void _onMessageReceivedInTheForeground(Map<Object?, Object?> data) {
AndroidNotificationDetails androidPlatformChannelSpecifics = const AndroidNotificationDetails(
'channel',
'My App Name',
channelDescription: 'New user registered',
playSound: false,
styleInformation: DefaultStyleInformation(true, true),
);
const IOSNotificationDetails iOSPlatformChannelSpecifics = IOSNotificationDetails(presentSound: false);
NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
log(json.encode(data));
// flutterLocalNotificationsPlugin.show(
// 0,
// 'New user registered',
// data['body'].toString(),
// platformChannelSpecifics,
// payload: data['title'].toString(),
// );
}
If I comment out flutterLocalNotificationsPlugin.show, the event fire only once as you can see in below screenshot.
but if I uncomment showing notification part which is the following code
flutterLocalNotificationsPlugin.show(
0,
'New user registered',
data['body'].toString(),
platformChannelSpecifics,
payload: data['title'].toString(),
);
The event fire endlessly (like in the screenshot below) and the notification keep appearing for each event continuously.
How come showing notification became some kind of loop and how should I fix this. Thanks in advance.
I end up showing the notification with SnackBar while the app is in foreground. While the apps is in background, the pusher beams package handle the notification and send it to notification center. Here's my code
initPusherBeams() async {
// Let's see our current interests
await PusherBeams.instance.setDeviceInterests([
'App.Models.User.${_user!.id}',
'debug-new'
]);
// This is not intented to use in web
if (!kIsWeb) {
await PusherBeams.instance.onMessageReceivedInTheForeground(_onMessageReceivedInTheForeground);
}
}
void _onMessageReceivedInTheForeground(Map<Object?, Object?> data) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(correctFont(data['body'] as String)),
duration: const Duration(milliseconds: 3000),
backgroundColor: brandBrown,
),
);
}```

Firebase Navigator is not working on onMessageOpenedApp

I read all topics on stackoverflow but none of them worked for me. I'm trying to use navigator when you click on the notification. Everything is working fine but when you click on it there's no error and no navigating, the notification just disappears. What can i do? I will share the code
initState(){
super.initState();
var initializationSettingsAndroid = AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettings = InitializationSettings(android: initializationSettingsAndroid,);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
FirebaseMessaging.onMessage.listen((event) {
LocalNotificationService.display(event);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Get.to(Conversa()); // I've tried to use navigator too, it not worked
});
}
OBS: If i try to use navigator inside onMessage it works but i don't want to automatically send the user to the x page
Use onMessageOpenedApp only when the application is in the background, not foreground or terminated.
A Stream event will be sent if the app has opened from a background state (not terminated).
See onMessageOpenedApp for details.
For foreground & background you can set the payload in flutter_local_notification from onMessage.
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
if (notification != null && !kIsWeb) {
String? payload = message.data;
flutterLocalNotificationsPlugin.show(
...
payload: payload);
}
});
Then, use payload value to manage your navigate in onSelectNotification
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String? payload) async {
// Navigate
});

FirebaseMessaging.instance.getInitialMessage() is not called in terminated state

FirebaseMessaging.instance.getInitialMessage() is not called in terminated state when we click notification that contains message data like this ,instead it is displaying screen from splash screen
{
"registration_ids": [
""
],
"data": {
"title": "Flutter9 Object Notification.3...",
"body": "this is flutter Data Object notification test message from",
"android_channel_id": "dgdgsdfgs",
},
"android":{
"priority":"high"
}
}
Given that you not displayed how you setup your fcm , here is how to go about it
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
/// To verify things are working, check out the native platform logs.
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
print('Handling a background message ${message.messageId}');
}
in main.dart
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
// setup displaying notifications
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title// description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
handle message call this in your initstate
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
// do message things
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
showMessage(message: message);
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: IOSNotificationDetails(subtitle: notification.title)));
}
});
incase you need to navigate on receiving a message
void showMessage({required RemoteMessage message}) async {
if (message.data['route'] == "mypage") {
var myparams = message.data['payload'];
Navigator.of(context).push(MaterialPageRoute(
fullscreenDialog: true,
builder: (_) {
return MyPage(
params:myparams,
);
})); ...
With FCM, you can send two types of messages to clients:
Notification messages, are sometimes thought of as "display messages." These are handled by the FCM SDK automatically.
Data messages, which are handled by the client app. "
https://firebase.google.com/docs/cloud-messaging/concept-options
What you are trying to send is a data message, my best guess is that the firebase SDK does not recognize the data message so it does not trigger the firebase message event listener. Your notification must have a 'notification' field for firebase SDK to listen to.

flutter - don't show notification when user is on certain page

My app has chatting function. And I have implemented Firebase Cloud Messaging and Local Notification.
So when someone sends me a message, notification(one inside android status bar) and local notification(one on the upper part of the screen that holds for like 3 seconds) is shown. They show up when app is opened, on background, and also when app is terminated. (So far so good)
But I don't want both notifications(1. fcm notification, 2. local notification) to show up when I'm already in the chat page with that person. And I have no idea where to start.
Below is my code for handling fcm and show local notification. They are inside main.dart and the main function calls initializeFCM before returning my root page.
Future<void> initializeFCM() async {
await Firebase.initializeApp();
FirebaseMessaging messaging = FirebaseMessaging.instance;
// Firebase Messaging
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
// print('User granted permission');
} else
if (settings.authorizationStatus == AuthorizationStatus.provisional) {
// print('User granted provisional permission');
} else {
// print('User declined or has not accepted permission');
}
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage = await messaging.getInitialMessage();
if (initialMessage != null) {
handleMessage(initialMessage);
}
// initialize local notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// terminated app을 local notification 눌러서 열었을 때 - payload가 정상적으로 동작하지 않음
final NotificationAppLaunchDetails? notificationAppLaunchDetails = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
final didNotificationLaunchApp = notificationAppLaunchDetails?.didNotificationLaunchApp ?? false;
if (didNotificationLaunchApp) {
onSelectNotification(notificationAppLaunchDetails!.payload);
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
showLocalNotification(message);
});
FirebaseMessaging.onBackgroundMessage(showLocalNotification);
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
}
void handleMessage(RemoteMessage message) {
if (message.data["screen"] == "message") {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => MessageListPage(),
)
);
}
}
Future<void> onSelectNotification(payload) async {
if(payload != null) {
Map<String, dynamic> data = json.decode(payload);
if (data['screen'] == "message") {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => MessageListPage(),
)
);
}
}
}
Future<void> showLocalNotification(RemoteMessage message) async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
// String screen = message.data['screen'];
// iOS heads up notification setting
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
// android channel setting
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.max,
);
// initialize local notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin.initialize(InitializationSettings(
android: AndroidInitializationSettings('#drawable/mentea_ic_stat_name'),
iOS: IOSInitializationSettings()),
onSelectNotification: onSelectNotification);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
// If `onMessage` is triggered with a notification, construct our own
// local notification to show to users using the created channel.
if (notification != null && android != null) {
// print('Message also contained a notification: ${message.notification}');
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
'high_importance_channel', //channel.id,
'High Importance Notifications', //channel.name,
icon: android.smallIcon,
color: primaryColor,
// other properties...
),
),
payload: json.encode(message.data)
);
}
}
I don't know if you still have this problem, but I'll post my solution here.
It happens that when we send a push notification with the notification message feature, the FCM plugin automatically sends a notification on the device if the App is in background and finished, where we can only customize the foreground notification through Local Notifications or other solutions within of the App. So the solution pointed out in the Firebase documentation for this situation is to send the push notification only as a data message, without including the notification object. Below I show the examples and the documentation link.
Documentation: https://firebase.google.com/docs/cloud-messaging/concept-options?authuser=1&hl=pt#notifications_and_data_messages
Combined notification example:
const payload = {
notification: {
title: '$FooCorp up 1.43% on the day',
body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
},
data: {
stock: 'GOOG',
open: '829.62',
close: '635.67'
}
};
Notification example with data message only:
const payload = {
data: {
score: '850',
time: '2:45'
}
};
Notification example with notification message only:
const payload = {
notification: {
title: '$FooCorp up 1.43% on the day',
body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
}
};
So, so that you can customize all forms of notification (foreground, background and terminated), send a push notification through your backend as a data message only.