As of now, I am using Firebase Cloud Messaging as my app's notification system. From my understanding, even the largest companies use GCM, which is now being replaced with FCM. I am stuck, however, with the limitations imposed by sending things as a "notification" pay load.
Firebase recieves data messages in OnMessageRecieved, and I am able to get my exact desired behavior through using this. However, for the past three months I noticed that my app's notifications were simply not working because data payloads aren't received when the app is in the background/ inactive. This is very frustrating as the only workaround I have found to actually send notifications that alert users is through sending notification payloads.
I don't know how to get my desired behavior with the notification payload as I have been with data payload, but I realize that having notifications display perfectly when the app is in the foreground is pointless if they don't display at all when the app is in the background.
What I'm wondering, and what I'd really appreciate guidance on, is if somebody could recommend a way to display notifications with my desired style rather than the default Firebase notification style. Just to elaborate, I currently have a fully functional system of allowing users to respond to messages through the notification and without opening the app, but only through the data payload.
I know there is a way to somehow send notifications in a customized fashion (adding intents, buttons, etc) when the app is in the background or not running because this is done by Facebook, WhatsApp, and many other apps on the market. I am aware of something called AlarmManagers, but unsure of how I could use them to get my desired behavior, or if this is what people use anyways.
Thank you, and please let me know if there is a way to customize the payload when the app is in the background or inactive, through onMessagesRecieved or any other methods. As of now, the only other solution would be to somehow send the message's contents to a service, but I've faced issues where services could not display notifications in the background without crashing the app and without being very hacky.
The only way I came up with is to send the data payload only, which should be delivered to the onMessageReceived callback despite the app's status (foreground/background).
Then you put all required fields to the data payload and build a notification from it. Here the map "data" is from remoteMessage.getData()
private void sendNotification(Map<String, String> data) {
String body = Optional.ofNullable(data.get("body")).orElse("");
if (body.isEmpty()) {
return;
}
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Uri sound = getSoundUri(Optional.ofNullable(data.get("sound")).orElse(""));
String defaultChannel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? NotificationChannel.DEFAULT_CHANNEL_ID
: DEFAULT_CHANNEL_ID;
String channel = Optional.ofNullable(data.get("android_channel_id")).orElse(defaultChannel);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channel)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(getString(R.string.app_name))
.setContentText(body)
.setAutoCancel(true)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setContentIntent(resultPendingIntent);
if (sound != null)
notificationBuilder.setSound(sound);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null)
notificationManager.notify(0, notificationBuilder.build());
}
Related
about event for click on notification:
I am searching since yesterday about that , what I found/understood: in FirebaseMessagingService will receive notification data , after will fire local notification, so need to add event in that local notification, I tried to add that many times with many ways but nothing worked …
after I tried to deleted notification files (firebase notification files, and local notification files) but still can receive notification. do you know how to know if the user clicked on the notification ?
To receive messages, use a service that extends FirebaseMessagingService. Your service should override the onMessageReceived and onDeletedMessages callbacks. It should handle any message within 20 seconds of receipt (10 seconds on Android Marshmallow). The time window may be shorter depending on OS delays incurred ahead of calling onMessageReceived. After that time, various OS behaviors such as Android O's background execution limits may interfere with your ability to complete your work.
For further info. you can visit the official website:
Link: https://firebase.google.com/docs/cloud-messaging/android/receive
Hope you'll get your answer here.
Step 1:
// Create an Intent for the activity you want to start
Intent intent = new Intent(this, MainActivity.class);
Step 2:
// Create the PendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(this, Calendar.getInstance().get(Calendar.MILLISECOND), intent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
Step3:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID, builder.build());
Whenever a user clicks on notification MainActivity will be opened.
Here is details implementation of Android Notification Sample https://github.com/android/user-interface-samples/tree/master/Notifications
I have implemented firebasse notification functionality in my chat app and everything is running fine but now while testing in Android os 8.0 and 8.1 when app is in background and if user is getting 4 or more than 4 notification then its combined in group and when user click on group then not getting intent and app is restarted.
If user tap on single notification then I am able to send him in specific screen.
I want Notification data or chat id so I can send him in specific screen but not getting any data in intent.
I have searched similar kind of question in stackoverflow but still not getting proper result.
Android: Clicking Grouped Notifications Restarts App
How to open non-launcher activity on notification group click
You can use setContentIntent to set the value of Intent like below
Intent intent = new Intent(this, SecondActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.your_notification_icon)
.setContentTitle("Notification Title")
.setContentText("Notification ")
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, mBuilder.build());
It will open SecondActivity (Replace the SecondActivity with your own activity)
I am having the same issue causing app restart in Oreo, after many tries i noticed that if when creating the notification i call .setGroup(string) the system no longer groups the notifications.I am creating the notifications from a service. This is not a solution i know but not grouping is a lesser evil than app restart.
I'm sending notifications from my Flask server using PyFCM, and I'm testing it on a single Android device. The test is like this: I am signed in as user A, and I make a comment on a post of user B which should display a push notification once B signs in. Here is how I send the notification from my server:
registration_id="<device_registration_id>"
message_body = "A has commented on your post."
data_message = {"sender": current_user.id}
result = push_service.notify_single_device(
registration_id=registration_id,
message_body=message_body,
data_message=data_message
)
And this is how I receive the message in the Android's Firebase messaging service:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent resultIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT):
String senderId = remoteMessage.getData().get("sender");
if (senderId != currentUser.id) {
NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder(this, "default_channel")
.setSmallIcon(R.drawable.android_icon)
.setContentTitle("New Comment")
.setContentText(remoteMessage.getNotification().getBody())
.setAutoCancel(true)
.setSound(soundURI)
.setContentIntent(resultIntent);
NoticationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, mNotificationBuilder.build());
}
}
As you can see, I have this condition: senderId != currentUser.id before actually composing the notification. It's because I'm using one device to send and receive the notification so there's only one registation_id/token for both users A and B. If I remove that condition, user A will receive the notification right after commenting on B's post. I want to ensure that B is the one who receives the notification. However, after logging out as A and logging in as B, I couldn't see any push notification.
I think onMessageReceived is only being triggered once. Say, I'm trying to send a notification from my server to all users, and I receive it while logged in as A. I clear the notification tray, log out, and log in as B, but I don't see another instance of the notification.
This is working as intended. From your post, I assume that you are not specifically deleting the registration token i.e. users of the same device re-use the same token. So the flow now looks like this:
User A signs in, so deviceToken = A.
You send a message from your server to deviceToken.
deviceToken receives the message, but you do not display it.
User A signs out, User B signs in, now deviceToken = B. Note: Same deviceToken, just different user.
In step 4, you're still expecting a message to arrive, but technically, it already did when User A was still signed in. onMessageReceived won't trigger again since it already received the message as expected.
In order to test your desired behavior, you would need two devices. I'm also actually doing this to an app I made (checking the senderId with the currentUser id), so I think it should work as well for you.
Also, the usual and suggested flow with FCM when signing out is you have to invalidate the token -- see my answer here for more details.
I have an app where the user can receive multiple notifications for things they need to do. The user has a choice of making some of these notifications persistent (which I achieve by calling NotificationCompat.Builder.setOngoing). At least on my version of Android which is Nougat, when more than three notifications are posted by my app they get bundled together into one notification, which makes all of them dismissible to the user in one swipe. This makes the previously persistent notifications no longer persistent. Is there a way to programmatically instruct Android not to bundle my notifications?
This is the code I use to build the notification and display it:
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(eventName + " " + notificationText)
.setDefaults(Notification.DEFAULT_ALL)
.setOnlyAlertOnce(true)
.setContentIntent(eventListPendingIntent);
if (goalInfo.goal.persistNotification) {
builder.setOngoing(true);
} else {
builder.setAutoCancel(true);
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(eventType.value(), builder.build());
Thanks, Nir
As per Google docs, notifications from the same app would be bundled automatically -
Note: If the same app sends four or more notifications and does not
specify a grouping, the system automatically groups them together.
So in your case, what you can do is , instead of system applying the default grouping, you can separate your notifications into two groups using a separate group key for the persistent notifications and one for the non-persistent ones.
Check the Google docs. The method Builder.setGroup() on NotificationBuilderCompat takes a string parameter which is the key.
There is a related method Builder.setGroupSummary which you should call on your Builder
Hope this is clear.
I have the following notification logic inside a class that extends GcmListenerService, and gets called when one notification arrives. Then, when clicked, the app takes you to MainActivity where the notification is displayed properly.
public static void mostrarAvisoBarraEstado(Context context, String alerts)
{
Intent notificationIntent = new Intent(context.getApplicationContext(), MainActivity.class);
notificationIntent.putExtra("alerts", alerts);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, new Random().nextInt(),
notificationIntent, 0);
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle(context.getString(R.string.app_name))
.setContentText("Alert received")
.setSmallIcon(R.drawable.nubeazul)
.setOnlyAlertOnce(true)
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setGroup(GRUPO_ALERTAS)
.setGroupSummary(true)
.setAutoCancel(true)
.build();
//notificationManager.notify(0, notification);
notificationManager.notify (new Random().nextInt(), notification);
}
So, right now, each one is displayed separately, and if they build up, the result is rather ugly with all the notification bar full of little icons. Can you guys help for an elegant solution since I am kindda new to Android? Thanks a lot!
NEW STUFF ADDED today!
If I take the notify random out, leaving something like notificationManager.notify(0, notification);, I will get just one notification, but nothing else, then when it launches MainActivity (its onResume() method) it will only display one notification and all the "piled up ones" are just discarded when clicked on the one notification. What I want to achieve is that while maintaining a clean display, i.e: one group notification for all GCM, if I click on the group, I will get each and every notification displayed throught the Alerts.class (something like looping through the notifications, and starting the activity Alerts for each one.
#Override
protected void onResume()
{
super.onResume();
if (getIntent().hasExtra("alerts"))
{
Bundle extras = getIntent().getExtras();
Intent intent = new Intent(this, Alerts.class);
intent.putExtra("alerts" , extras.getString("alerts"));
startActivity(intent);
getIntent().removeExtra("alerts");
}
}
Then the Alerts class will nicely display the alert which it does, but one per notification.
So I tried out your code and managed to see reproduce what you were encountering (I just manually created dummy notifications). So the reason that the Notifications were piling up was because the id you are passing in the notificationManager.notify() is different from one another. As to what I have observed on the Notification and NotificationManagers behavior so far, the id indicated in notify() it kinda represents the id location/position (not sure what to call it) of the Notification that is under the NotificationManager, not an id of the Notification itself.
Imagine the NotificationManager as an array or list. If for example, you have 3 visible notifications on the Status Bar:
Notification 1, Notification 2, Notification 3 and their ids are as follows: 0, 1, 2.
If you generate a new Notification 4 then called notify passing it as a parameter, and the id 1, the notifications that will be currently shown in the NotificationManager would result to something like this:
Notification 1, Notification 4, Notification 3 and their ids are as follows: 0, 1, 2.
So the reason that you're notifications are piling up and NOT grouping together is because you end up with different ids when calling notify() while passing new Random().nextInt().
As per the behavior that I think you are aiming for -- Joining the notifications from your app into one -- the implementation is simple when understood, but I think it's still a little bit tricky. It's like you have to check first if there is more than 1 notification already, then if yes, you create a summary notification with the details and you show it alone (mind the id ;)) and all of those other stuff. I found this blog though that I think might help you with it. Or you can simply just check out the official docs on Stacking Notifications.
So bottom line, simply use a single id to pass in notify() when it comes to your apps Notifications. Hope this helps. Cheers! :D