5

I am trying Implemented push notification service using Firebase Cloud Messaging in my Flutter app. This is how FCM documentation says we should handle notifications, according to the current state (foreground, background or terminated) of our app:

Foreground: we have an onMessage stream, that we can listen to, but FCM will not show any notification when in foreground state, so we have to use FlutterLocalNotificationsPlugin for that, this is my implementation of it:

FirebaseMessaging.onMessage.listen((RemoteMessage remoteMessage) {
      // calling flutter local notifications plugin for showing local notification
      scheduleNotification(remoteMessage);
    });

in scheduleNotification method I call the FlutterLocalNotificationsPlugin().show() method, and everything works as expected till now.

The problem starts here:

Background, Terminated: Firebase automatically shows a notification in this state and it has a onBackgroundMessage. method, to which we can pass an BackgroundMessageHandler which runs after FCM has shown the notification. This is my implementation of the background handler:

Future<void> backgroundMessageHandler(
    RemoteMessage remoteMessage) async {
  RemoteNotification? remoteNotification = remoteMessage.notification;
  if (remoteNotification != null) {
    FlutterLocalNotificationsPlugin().show(
        remoteMessage.messageId.hashCode,
        remoteNotification.title,
        remoteNotification.body,
        NotificationDetails(
          android: AndroidNotificationDetails(
              _androidNotificationChannel.id,
              _androidNotificationChannel.name,
              _androidNotificationChannel.description,
              icon: 'launch_background',
              importance: Importance.max),
        ));
  }
}

Problem: Every time my app receives a notification from FCM, my app shows TWO notifications, one is shown automatically by FCM, and the second one is shown by the FlutterLocalNotificationsPlugin().show() method that i am calling in the BackgroundMessageHandler.

Tl:dr

How do I prevent FCM to show any notifications automatically and only show it via FlutterLocalNotificationsPlugin().show() method ?

One solution is, I don't send notifications from FCM and only send Data Messages, for which FCM doesn't show any notification. but, i don't think its the right way.

alankrit nayak
  • 121
  • 1
  • 7
  • 1
    Read this, maybe it can help: https://stackoverflow.com/questions/66934956/how-to-use-firebase-cloud-messaging/66935971?noredirect=1#comment118360258_66935971 – Celt K. B. Apr 06 '21 at 20:29
  • What do you use to send your notifications? – Celt K. B. Apr 06 '21 at 20:30
  • @CeltK.B. I do need onMessage listener, as I mentioned in the question, when the app is in foreground, FCM does not show any notification, and only the FlutterLocalNotifiationPlugin does. Which is exactly what I want. The problem is, when the app is in background, in this case FCM shows a notification and FlutterLocalNotificationPlugin also shows a notification, so I get 2 notifs, instead of one. I want FCM to not show a notification in any state. – alankrit nayak Apr 06 '21 at 20:40
  • Yo, is it possible to see your code? Just the `_firebaseMessagingBackgroundHandler()` part? Basically, I can only define this above `main() {}` and it is giving me such headache! If I declare it to somewhere else, then I get `Null check operator used on a null value` error. If I only send with `data` then it does not work on iOS? Did you make it work on iOS as well? – chichi Apr 28 '21 at 19:43

3 Answers3

7

I am answering my own question here, After some research, I found out in the FCM docs that it does mention to use data only messages if we want to handle displaying the notifications on client side. We can read about it here

Client app is responsible for processing data messages. Data messages have only custom key-value pairs with no reserved key names (see below).

Use notification messages when you want FCM to handle displaying a notification on your client app's behalf. Use data messages when you want to process the messages on your client app.

This thing is also mentioned in the flutter fire docs,

Your application code can then handle messages as you see fit; updating local cache, displaying a notification or updating UI. The possibilities are endless!

So that is the answer I guess, I just don't have to use the "notification" field when delivering an FCM message, and FCM Plugin on the client will not show notification automatically. I still think this should be made more clear in the docs, caused a lot of confusion and research and I still think its a bit odd, when our intention is to show notification to the user, but we are still omitting the "notification" field.

alankrit nayak
  • 121
  • 1
  • 7
  • I'm facing the same issue could you please share your code? my firebase always call the notification in the background and display the content in the notification center so I have double notifications ☹️ – Tabarek Ghassan Jan 16 '22 at 12:42
0

Remove the FlutterLocalNotificationsPlugin().show call from the code above. You do not need to manually show the notification.

As you said, the notification is already shown when this code is run.

Or am I missing something?

Michele Volpato
  • 700
  • 6
  • 14
  • FlutterLocalNotificationsPlugin().show I do need this call, bcz i want to prefer Local Notification over the one that is shown automatically by FCM, bcz of customisability reasons. Is there anyway i can prevent FCM from showing notifications automatically and only use FlutterLocalNotificationsPlugin().show ? basically i want to do the exact opposite of what you are suggesting. – alankrit nayak Apr 06 '21 at 20:51
  • You might want to look into silent push notifications in iOS. I do not know if there is an equivalent in Android, nor if Firebase allows them. Maybe [this answer](https://stackoverflow.com/a/37621274/13876163) can help. – Michele Volpato Apr 06 '21 at 20:56
  • as i mentioned in the last paragraph of my question I did think of using "Data only" messages, if that's what you are suggesting, but i don't think that's the ideal way to do, I think i read somewhere that "data only" messages, should be used for non-trivial task, notification is not one of them – alankrit nayak Apr 06 '21 at 21:08
  • But thanks for the link to the answer, if there is no other way around it, i'll end up using data only messages. : ) – alankrit nayak Apr 06 '21 at 21:15
  • I don’t think that just showing a local notification is that intensive to be considered non trivial. Personally I would consider making the push notification work for the specific case, but I have no idea of the specific case and the customization you need. Hopefully someone will be able to tell you if you can hide the push notification or not. – Michele Volpato Apr 06 '21 at 21:24
  • But at the end of the day, our intention is to show a notification on the device, for which, FCM recommends using the "notification" field, and not the "data" field. So its only ideal to deliver the notification using the "notification" field. Its just that we don't want to use the FCM plugin to show notifications on the client side, which should be independent of how FCM server is delivering it. – alankrit nayak Apr 06 '21 at 21:35
  • Atleast that's what i think, if they are not as independent to each other as i think they are, then i'll eventually have to use the "data" field and deliver a data only message. – alankrit nayak Apr 06 '21 at 21:36
0

I had the same problem at the beginning as a solution I omitted the notification sending in the json but after trying and testing, I discovered that I could send notification and data without having the double push notification problem, it was solved.

solution: check your onbackgroundhandler and validate the data

if (message.data.message ['android_channel_id'] == my channel) {

  flutterLocalNotificationsPlugin.show();
}
cigien
  • 57,834
  • 11
  • 73
  • 112