Firebase merge similar notifications in Android - android

We are using Firebase in a SIP app to send us missed call notifications and chat notifications whenever the app was offline.
While sending and receiving works fine, we have the effect on the Android client, that 5 missed calls obv produce 5 missed-call-notifications, filling up the notification bar on the client device.
How can we merge those notifications together, to just show a single "5 missed calls" notification?
Is there any additional flag (like grouping) we can put in the data or notification part of the message?
Here is an example of our current missed call notification:
{
"to":"<<FCMToken>>",
"priority":"high",
"notification":{
"title":"<<Displayname-of-Caller>>",
"text":"<<Date-and-time-of-call>>",
"icon":"icon_notification_missed",
"click_action":"MISSED_CALL"
},
"data":{
"type":"sip-call-missed"
}
}
So what's the trick in combining them together as one?

We found the correct solution.
There are more existing keywords for the notification content.
The one we needed was "tag".
We can even localize the client-side text of the notification by supplying a resource name in loc keys.
Here is a correct message that can be bundled together:
{
"to":"<<FCMToken>>",
"priority":"high",
"notification":{
"title_loc_key":"notification_missed_call",
"tag":"MISSED_CALL",
"body_loc_key":"notification_missed_call_multiple",
"body_loc_args":["<<missed_call_count>>"],
"icon":"icon_nav_main_chat",
"click_action":"MISSED_CALL"
},
"data":{
"type":"sip-call-missed"
}
}
The tag will be merged by the client ... say: they will replace each other. Whenever a notification with a tag arrives, it replaces all other existing notifications with the same tag.
So the trick here is, to supply a running count <<missed_call_count>> (which the server has to count), so the client can show an increasing number, like "5 missed calls".
The string "%d missed calls" is stored in the client side string resource named "notification_missed_call_multiple".

Related

Firebase notification won't default to `title_loc_key` if normal `title` is set

I'm using com.google.firebase:firebase-messaging:20.0.0 on Android. When I try sending a notification like the one below it always shows the normal title and body instead of title_loc_key and body_loc_key when they are presented in the app! The fun thing is that it's not the case in iOS. In iOS it will always try to first show the localized resources and if it couldn't find them, it will default to normal ones.
{
"to" : "f6_numko7IQ:APA91bFrTN0fmThFDeAFy2...",
"collapse_key" : "type_a",
"notification" : {
"title_loc_key": "resource_name_1",
"body_loc_key": "resource_name_2",
"title": "Default Title",
"body": "Default Body!"
}
}
Is this a known issue? Is there a get around for it?
The solution is to remove the "title" and "body" entries. I know it should work like on iOS but currently it's not.
{
"to" : "f6_numko7IQ:APA91bFrTN0fmThFDeAFy2...",
"collapse_key" : "type_a",
"notification" : {
"title_loc_key": "resource_name_1",
"body_loc_key": "resource_name_2",
}
}
For Android: Using the "v1" api from firebase remove "title" and "body" from root "notification: {....}" and add into the "android": {
"notification": {
"title_loc_key": "push_notification_title",
"body_loc_key": "push_notification_body"
}
},", should work.
But you need to keep in mind the following:
The push notification will be displayed by default by firebase SDK based on the com.google.firebase.MESSAGING_EVENT, when the app is in the background --> opened (the process is in the background) and Notification permission is allowed. Also, you need to be sure that your app has already a channel created with the default_channel_id you defined in the manifest file. For this case, you will not be notified of the onMessageReceived callback provided by "FirebaseMessagingService".
When the app is in the foreground you will not receive any firebase notification, visible on the screen. Based on the Channel you have created at point 1) you need to trigger the notification display if required, by creating a NotificationBuilder .... and displaying it. This catch must happen inside the: onMessageReceived callback provided by "FirebaseMessagingService"
When the app is closed and notification is allowed the push notification will be displayed by default by firebase SDK based on the com.google.firebase.MESSAGING_EVENT. However, if the notification received by the device contains some data: {} payload that can be handled into the onCreate lifecycle method from activity by accessing the this.intent.extras. You will not be notified of the onMessageReceived callback provided by "FirebaseMessagingService".
If notification is disabled you will not get any push notification displayed visually but when the app is in the foreground you will be notified into the onMessageReceived callback provided by "FirebaseMessagingService". When the app is closed or in the background, you will get nothing.

How to collapse multiple notifications into a single one using Firebase?

I have function in Firebase Cloud Functions which is used to send notifications to specific users within my app and has as the notificationContent the following code:
const notificationContent = {
notification: {
title: "My Notification Title",
body: "My Notification Body",
icon: "default",
sound : "default"
}
};
I have tried to use collapse_key: "unique_key" but it has no effect. I read the has an effect only when the device is offline. I also have used a tag: "unique" but every time a new notification arrives, it will override the oldest one.
I there any way in which I can achieve this with Firebase? If I receive more then one notification, to be grouped in a single one?
Thanks in advance!
If you want to use more customizable and advanced notification features.
You should only send FCM with data payload, and create notification at android client side.
Remember that if you send FCM with notification payload or notification + data payload, the notification will be created by android core system and BroadcastReceiver's onReceive method won't being called if your app is on background.
If you send FCM with data payload, it will call onReceive all the time, so you can produce custom notification manually at android client side. (most app uses latter method.)
I hope this link would be helpful.
I had this same confusion and realized I misunderstood what collapseKey and tag are for.
collapseKey will limit the number of notifications a client receives while they're offline, tag is what will stack notifications together in the drawer.
So for a typical cloud function, it should look like this:
const notification = {
notification: {
'title': 'Interesting title',
'body': 'Hello, world'
},
'data': {
'whatever': whatever,
},
'android':{
'collapseKey': collapseKey,
'priority': 'high',
'notification': {
'tag': tag,
}
},
'token': fcmToken
};
admin.messaging().send(notification)
Note that the "tag" parameter sits inside of the android notification, not the top-level notification.
The easiest and most flexible solution is to extend the FirebaseMessagingService and handle the notification yourself. But first instead of using notification on your notificationContent in your cloud function, you have to change that to data so that you send a data message instead of a notification message. The difference is that the notification message will have an implicit collapse key (the package name of the app), while the data message won't have one. But the data message needs to be handled on the client or else it won't be displayed.
Here's a sample of what you'll need for your FirebaseMessagingService:
public class MyFCMService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getNotification() != null) {
//this notification was sent from the Firebase console, because in our cloud function, we are using the DATA tag, not the notification tag
//so here we have to handle the notification that was sent from the console
...
} else if (remoteMessage.getData().get(KEY) != null) {
//this data message was sent from our cloud function
//KEY is one of the keys that you are using on the cloud function
//in your example, you are using the keys: title, body, icon, sound
//display the notification to the user
...
notificationManager.notify(TAG, ID, notificationBuilder.build());
//you have to use the same TAG and the same ID on each notification if you want your 2nd notification to simply update the text of the first one, instead of showing as a new notification
}
}
}
PS. When you send a notification from your cloud function (well if you use the data tag, it's actually a data message, not a notification message), then this method will be called, regardless if the app is in the background or in the foreground. HOWEVER, when you send a notification from the firebase console, this method will be called ONLY if the app is in the foreground. If the app is in the background, the Firebase SDK will handle the notification and show it to the user. In some cases, it makes sense to show a notification only when the user is not running the app, for example if you want to advertise some new features of the app. In that case, what you can do is use a unique tag on the notification console (e.g. "display_in_foreground") and check that tag on the client. If you have set that to true, you can show the notification even to users that are currently running the app, or if it's false you can choose not to show the notification. This check will happen only if the app is in the foreground. If it's in the background, this won't be called at all and the SDK will handle to show the notification.

FCM Push notifications does not show heads display on notification on top of screen

We are using firebase push notification in Android and in iOS. The push is sent using FCM REST API call. Push type is notification with extra data node.
Here is a sample payload:
{
"notification" : {
"title": "title text",
"body": "message body text",
"sound": "default"
},
"data": {
"messageType": "xxx"
},
"to": "yyy",
"priority": "high",
"time_to_live": 0
}
This type of push notification does not show a heads up display when the app is in background and phone is on. -- Notification just are added to notifications bar but are not sneak peaked to user at the top of the screen. -- no matter if the current app is full screen app or not.
One solution that I have tried and is working is to shift to pure data message where we will not send any notification node, but just the data node and write the code to show notification ourselves and set notification priority to Max (ie .setPriority(Notification.PRIORITY_MAX)) on notification builder object.
But this seems to have issues on iOS where data only pushes are not received/shown to user if the app killed by user.
So is there any workaround to this? any solution that works on Android, but also does not break iOS.
You should set the NotificationPriority to PRIORITY_HIGH or PRIORITY_MAX for Android to show the notification. See Android Notification and Notification Priority for more details.
You should set these values using the constants, not using the strings. E.g.
{
token,
android: {
notification:
{
title,
body,
// See https://developer.android.com/reference/android/app/Notification#PRIORITY_MAX.
// This is deprecated in Android API level 26, but works for older versions.
notification_priority: 2,
// Always allow Android users to see the message in its entirety.
// See https://developer.android.com/reference/android/app/Notification#VISIBILITY_PUBLIC
visibility: 1
}
}
}

Customize Baidu Push JSON Payload

I am using a rest API to send Baidu Push notifications. I don't have access to Android's notification builder classes, so I can't, for example, use notificationBuilder.setPriority(2);. Really the main thing that I need to know is how to set the priority of a Baidu Push notification to MAX, using JSON only.
According to this website, here are all of the keys and values for a Baidu JSON payload:
{
//android必选,ios可选
"title": "hello" ,
"description": "hello world"
//android特有字段,可选
"notification_builder_id": 0,
"notification_basic_style": 7,
"open_type":0,
"net_support" : 1,
"user_confirm": 0,
"url": "http://developer.baidu.com",
"pkg_content":"",
"pkg_name" : "com.baidu.bccsclient",
"pkg_version":"0.1",
//android自定义字段
"custom_content": {
"key1":"value1",
"key2":"value2"
},
//ios特有字段,可选
"aps": {
"alert":"Message From Baidu Push",
"sound":"",
"badge":0
},
//ios的自定义字段
"key1":"value1",
"key2":"value2"
}
I assume I need to set the values of notification_builder_id, but as it simply takes an integer as a the value, I am not sure how to create the notification to correspond with the id.
I was able to find out how to set the priority to high, in order to make the notification appear as a banner, as opposed to just an icon in the status bar.
In the client app, you need to set the notification builder, and give it an id, like so (note that I'm using Xamarin Forms, but the logic is the same if you are using native Android. Also, this code should be placed directly after the PushManager.StartWork() method call, most likely in your activity's onCreate() method):
BasicPushNotificationBuilder builder = new BasicPushNotificationBuilder();
builder.SetNotificationFlags(
(int)NotificationFlags.AutoCancel |
(int)NotificationFlags.HighPriority |
(int)NotificationFlags.ShowLights);
builder.SetNotificationDefaults(
(int)NotificationDefaults.Lights |
(int)NotificationDefaults.Vibrate);
builder.SetStatusbarIcon(Resource.Drawable.icon);
// the second parameter is the id. This is the id that you need to set
// in the JSON payload in order for the incoming notification to appear
// in this way.
PushManager.SetNotificationBuilder(Xamarin.Forms.Forms.Context, 1, builder);
And then for the payload, its simply like this:
{"title":"My Title","description":"my description","notification_builder_id":1}
Again, note that the value of notification_builder_id has to correspond with the second parameter in the SetNotificationBuilder() method.

Gmail API labels Android

I am using the Gmail API for Android for an application to send emails.
I want to send the mails such that they are received in the Social group of messages.
So is it possible in any way that I can set the labels for an email while sending it using the Gmail API ?
It is possible for us to set labels while sending mails through mail.google.com so how can the same be achieved with the Gmail API ?
You cannot specify the labels message should have when sending it. Under what tab certain messages should end up under is up to the user.
But if you are sending a message to the user himself howewer, it's not that hard to modify the message once it has been sent. When you send a message, you get all the label that were applied to the message in the response. Just send a message, and then modify the labels, and you are done.
Here's an example (with regular http-requests, but you could do the same with one of the client libraries):
// Base64-encoding the message and making it url-safe by replacing
// all '+' with '-', and all '/' with '_'.
btoa("To: example#gmail.com\n" +
"From: example#gmail.com\n" +
"Subject: Cool man\n\n" +
"Here is the message").replace(/\+/g, '-').replace(/\//g, '_');
// => "VG86IGV4YW1wbGVAZ21haWwuY29tCkZyb206IGV4YW1wbGVAZ21haWwuY29tClN1YmplY3Q6IFRoaXMgaXMgdGhlIHN1YmplY3QKCkhlcmUgaXMgd2VyZSB0aGUgbWVzc2FnZSBnb2Vz"
Sending the message:
POST https://www.googleapis.com/gmail/v1/users/me/messages/send
{
"raw": "VG86IGV4YW1wbGVAZ21haWwuY29tCkZyb206IGV4YW1wbGVAZ21haWwuY29tClN1YmplY3Q6IFRoaXMgaXMgdGhlIHN1YmplY3QKCkhlcmUgaXMgd2VyZSB0aGUgbWVzc2FnZSBnb2Vz"
}
Response
{
"id": "150866b2f6956617",
"threadId": "150866b2f6956617",
"labelIds": [
"SENT",
"INBOX",
"UNREAD"
]
}
Then, I just the add the CATEGORY_SOCIAL-label to get it to show under the social-tab (removing the INBOX-label will not show it at all).
Request
POST https://www.googleapis.com/gmail/v1/users/me/messages/150866b2f6956617/modify
{
"addLabelIds": [
"CATEGORY_SOCIAL"
]
}
Worked great!

Categories

Resources