send multiple notifications using FCM, but within the same server side, saying that there is multiple notification types, probably with different data payloads and different notification titles, i want the the notification manager to be able to differentiate between each notification on the client side and send them to different Notification Channels?
EDIT
I tried setting notification_id and it does not work.
EDIT:
I can add a Data payload and restrict the notification in one of my classes and add a switch statement which will divide according to my Notification but i need to handle the data in the background and not foreground.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
notificationSwitch(remoteMessage);
}
private void notificationSwitch(RemoteMessage remoteMessage) {
RemoteMessage.Notification notification = remoteMessage.getNotification();
if (notification.getTitle().equals("TypeOne")){
TypeOneSendNotification(remoteMessage);
}
else{
TypeTwosendNotification(remoteMessage);
}
}
//Ofcourse we are able to switch based on the title, or different data payloads
EDIT:
I converted into a data payload and edited the notification title to be able to switch the above edit
Create the notification_key, which identifies the device group by mapping a particular group (typically a user) to all of the group's associated registration tokens. You can create notification keys on the app server or on Android client apps.
please check this link
https://firebase.google.com/docs/cloud-messaging/android/device-group
I got this working by implementing a switch statement on the title is merely a hack but it definetly works
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
notificationSwitch(remoteMessage);
}
and in my notification switch function as i already have remoteMessage as an argument i will just implement my senders.
private void notificationSwitch(RemoteMessage remoteMessage) {
RemoteMessage.Notification notification = remoteMessage.getNotification();
if(notification.getTitle() != null){
switch (notification.getTitle()) {
case "SenderOne":
SenderOneSendNotification(remoteMessage);
break;
case "SenderTwo":
SenderTwoSendNotification(remoteMessage);
break;
case "SenderThree":
SenderThreeSendNotification(remoteMessage);
break;
case "SenderFour":
SenderFourSendNotificaation(remoteMessage);
break;
default:
DefaultSender(remoteMessage);
break;
}
}
Answering the question in the title: FCM from multiple senders but within the same app
If sender == Firebase Project then I don't think it is possible.
If sender == a client inside the same Firebase Project (like an iOS app, multiple servers, another Android app), then you need to create those apps inside your Firebase Project (for iOS and Android apps) and use the server key (for the servers)
If sender == function (like "Update Entity A", "show notification for promotion", etc), then you can use the data field inside the notification. We usually add an action field inside the data field. Both the receiver (iOS or Android app) and the sender (usually a server, but can also be a mobile app) know the list of possible actions. Receivers know what to do when they receive them (if app receives "Update Entity A", then it starts the EntityAUpdateService).
Related
This push notification is used to notify when a new chat message is available. I want to do like Instagram, that is to say, the message into this notification is updated at each new income message received, until the user open the chat.
So, how can I retrieve the message for this specific notification? Is it possible, or I have to save (in cache) the latest messages... ?
Thank you very much
I suggest saving messages in the database, and then in the function that sends notifications, get messages (probably recent unread ones - I don't know what your logic looks like in this case).
If there are more than one, use InboxStyle():
val otherMessagesToShow = getMostRecentUnreadMessages()
if(otherMessagesToShow.size > 1) {
val style = NotificationCompat.InboxStyle()
otherMessagesToShow.forEach { style.addLine(it) }
builder.setStyle(style)
builder.setNumber(otherMessagesToShow.size)
}
Finally, update the existing one (passing the same notificationID):
notificationManager.notify(notificationId, builder.build())
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.
I'm building an application using Ionic Framework that implements a chat function similar to good-old facebook messenger, in that i want to notify users of a chat message, but if they view it elsewhere, i want to remove the notification from their home screen.
I'm using firebase as a back-end for push notifications (though that could be changed i suppose).
I know that you can't expire a remote notification, but i've been told you can expire + remove a local notification, so my question is - can i reliably receive a remote notification, create a local one, and display that, and then in response to a notification with a scope of 'expire' or 'remove', delete a local notification so that my users don't see a duplication of information?
Most plugins tend to detect the status of the app and add a remote notification to the homescreen with the info you've pushed by default, is there a way to avoid this?
Thanks guys.
EDIT:
- Local notifications: http://ionicframework.com/docs/native/local-notifications/
- Firebase cloud messaging: https://github.com/fechanique/cordova-plugin-fcm
As far as I can tell there're no plugins which accomplish all what you need. However..
can i reliably receive a remote notification, create a local one, and display that, and then in response to a notification with a scope of 'expire' or 'remove', delete a local notification so that my users don't see a duplication of information?
Most plugins tend to detect the status of the app and add a remote notification to the homescreen with the info you've pushed by default, is there a way to avoid this?
Yes, by using silent notifications and building the local notification by yourself.
For a project I'm working in, I modified the plugin cordova-plugin-fcm to add support for (local on demand) notifications dismiss/display, send multiple notifications to the cordova app, and some PRs that are not included yet. Also I build the notification by myself, to have full control of what is displayed. You can take a look at the code to get some ideas.
In brief it works like this:
Firstly, I send a "silent" push to the app, which is not displayed by Android:
{
"content_available": true, // IMPORTANT: For Apple -> content-available: 1, for firebase -> content_available: true
"priority": "high",
"to": "/topics/all", // or to a fcm token
"data"{
"title": "My title", // this implies that you display the notification by yourself
"body": "My body", // this implies that you display the notification by yourself
"type": "NEW_USER_MESSAGE", // only relevant to this project
"userId": "1", // only relevant to this project
"timestamp", "150000000"
}
}
Note: If the payload have the "notification": {} item, Android will display it on the system tray (if the app is in background).
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages
Secondly, when the push arrives to the app (in onMessageReceived()), I build the local notification, assigning it a TAG and an ID. This is the way you can use to dismiss it later.
For example, you could create a local notification with the TAG "NEW_USER_MESSAGE" and ID 1 (a constant indicating a state of the message, or the user ID for example). Also, Android will replace notifications with the same TAG and ID, so this is another way to automatically replace notifications (for example if you send a generic message, like "New update available").
public static String TYPE_NEW_USER_MESSAGE = "NEW_USER_MESSAGE";
public static String TYPE_USER_LEFT_ROOM = "USER_LEFT_ROOM";
NotificationManager notificationManager =
(NotificationManager) _ctx.getSystemService(Context.NOTIFICATION_SERVICE);
// based in the type of the message you've received, you can stylize the notification
if (type.equals( TYPE_USER_LEFT_ROOM )){
notificationBuilder.setColor(Color.RED);
notificationBuilder.setLights(Color.RED, 1000, 500);
}
else if (type.equals( TYPE_NEW_USER_MESSAGE )){
notificationBuilder.setColor(Color.BLUE);
notificationBuilder.setLights(Color.BLUE, 1000, 1000);
}
Notification n = notificationBuilder.build();
notificationManager.notify(type, userId, n);
One advantage of doing it in this way, is that you have full control of the notification to be displayed, so you can stylize it like you want.
If you want to discard expired messages, you can check out the elapsed time between the sent timestamp and the current timestamp:
java.util.Date now = new java.util.Date();
java.util.Date sent_timestamp = new java.util.Date( Long.valueOf(timestamp.toString()) );
final Long elapsed_time = ((now.getTime() - sent_timestamp.getTime()) / 1000);
Log.d(TAG, "New message. sent " + elapsed_time + "s ago");
Thirdly, when the user clicks on a notification Android will launch your app, and the plugin will send the payload of the push message to the cordova view (onNotificationReceived()).
Once your app is opened and you have received the push message, you can dismiss it adding a new action to the plugin:
onNotificationReceived(data){
if (data.wasTapped === true){
if (data.type === 'NEW_USER_MESSAGE'){
FCMPlugin.dismissNotification(NEW_USER_MESSAGE, 1);
}
}
}
The Android action:
else if (action.equals( ACTION_DISMISS_NOTIFICATION )) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
try{
Log.d(TAG, "FCMPlugin dismissNotificaton: " + args.getString(0)); //tag
NotificationManager nManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(args.getString(0)/*NEW_USER_MESSAGE*/, args.getInt(1) /*1*/);
Log.d(TAG, "FCMPlugin dismissNotificaton() to remove: " + id); //tag
callbackContext.success();
}catch(Exception e){
callbackContext.error(e.getMessage());
}
}
});
https://github.com/TrustedCircles/cordova-plugin-fcm/blob/master/src/android/FCMPlugin.java#L286
And the method exposed to the cordova app:
// dismisses a notification by tag+id
FCMPlugin.prototype.dismissNotification = function( tag, userId, success, error ){
exec(success, error, "FCMPlugin", 'dismissNotification', [tag, userId]);
}
https://github.com/TrustedCircles/cordova-plugin-fcm/blob/master/www/FCMPlugin.js#L65
The only tricky bit with notifications in cordova/ionic is the JS part receiving the notification and triggering the Android code.
I used https://github.com/phonegap/phonegap-plugin-push library and its pretty straight forward.
There is a callback when notifications are received in JS(Cordova/Ionic), use this to render you notifications locally in Android.
P.S: Basel's answer tells you how to clear your notifications, so I decided to leave that bit out.
I am using cordova plugin add phonegap-plugin-push plugin for push notification
In forground notification works fine.and i can handle event also.
When my app is in background then i got notification as well but on click of push notification my event is not fire.
I am using below code
$cordovaPushV5.initialize(options).then(function() {
// start listening for new notifications
$cordovaPushV5.onNotification();
// start listening for errors
$cordovaPushV5.onError();
// register to get registrationId
if (PNdeviceToken == null) //becuase registration will be done only the very first
{
$cordovaPushV5.register().then(function(registrationId) {
// save `registrationId` somewhere;
window.localStorage.setItem('PNdeviceToken', registrationId);
$rootScope.fcmToken = registrationId;
console.log(registrationId)
alert("first time registered id -- " + registrationId)
})
} else {
$rootScope.fcmToken = PNdeviceToken;
alert("already saved registered id -- " + $rootScope.fcmToken)
}
});
$rootScope.$on('$cordovaPushV5:notificationReceived', function(event, data) {
console.log(event)
console.log(data)
})
When i tap on background push notiction then $cordovaPushV5:notificationReceived event not fire, How can I solve this problem?
How can i handle background push notification event?
I had the Same issue and got it resolved it after 2 days of research.
Handling the notification events is same whether the app is in foreground or background.
We have to set "content-available" : "1" in the data field while pushing notifications. Else it wont call notificationReceived event if app is in background.
Also note this is not possible as of now through Google Firebase Console.
We have to send our custom payload messages (data or notification or both) seperately using any one of the firebase servers.
Detailed info can be found on the plugin's GitHub Docs Page on background notifications.
Quoting from there -
On Android if you want your on('notification') event handler* to be called when your app is in the background it is relatively simple.
First the JSON you send from GCM will need to include "content-available": "1". This will tell the push plugin to call your on('notification') event handler* no matter what other data is in the push notification.
*on('notification') event handler = $cordovaPushV5:notificationReceived event in your case.
See this answer for sending custom payload messages using PHP and NodeJS
I'm using the Parse SDK to receive push notifications in my Android app. My backend sends a JSON formatted string with the contents of the push notification to be displayed in the notifications bar.
What I want to do is parse this JSON and depending on it's content, take the user to different parts of the app (Activities). I'm able to receive and parse the JSON fine, but how can I handle the actual action which is performed when the user taps on the notification in the notifications bar?
I know that I can configure the Parse SDK to open up different activities when I subscribe to a specific channel, like this:
PushService.subscribe(this, "testing", ActivityA.class, R.drawable.ic_push);
PushService.subscribe(this, "testing2", ActivityB.class, R.drawable.ic_push);
// etc
But this doesn't really help me, since I won't know which Activity to open until I actually receive the push notification and parse the JSON. So, what I'm looking for is something like:
public class PushReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
if(json contains id = 0) {
// open ActivityA when the user opens this notification
} else if(json contains id = 1) {
// open ActivityB when the user opens this notification
}
} catch (JSONException e) {
Log.d("", "JSONException: " + e.getMessage());
}
}
}
Any ideas how this can be accomplished using Parse? Thanks.
This is not a direct and good solution but i think it does the work (haven't tried it myself). You can use that broadcast receiver and call PushService.setDefaultPushCallback(context, ActivityAorB.class); based on your JSON data. This will set a default activity to be called when the push message is received so that this activity will open when the user taps on the notification.
Be sure to add this receiver to your manifest.
More info about broadcast receiver on parse