I am using FCM for Simple notification
When the app is in foreground, everything working properly. I am getting a notification plus the data message inside the onMessageReceived method.
But when app is in background, I am getting notification in system tray. And when I click on the control, it goes to the main activity. And When I parse intent.getExtras();, I am getting only this key data - google.sent_time, from, google.message_id, collapse_key.
How to get the notification message title and Message which is visible in system tray from intent.getExtras()?
I am using FCM console for sending notification I don't have my dedicated server to do this.
Code for receiving the message:
final Bundle extras = intent.getExtras();
final Set<String> keySet = extras.keySet();
final Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
final String key = iterator.next();
final Object o = extras.get(key);
System.out.println(key + ":" + o);
}
As seen in the Handling Messages for Android FCM docs, if the payload you sent has both notification and data, it will be handled separately. The notification part will be handled by the Notification Tray, while the data part will be in the extras of the intent.
AFAIK, there is no way to get the notification payload when the app is in background (always handled by the Notification Tray). However, what you could do is add custom key-value pairs to your data payload instead, like so:
{
"data": {
"notification_title": "title here",
"notification_message": "message here"
}
}
Of course you'll have to make sure that the data value for notification_title and notification_message is the same as to what you set it in the notification payload. Then just retrieve it from the Intent extras like usual.
Firebase Notfication will behave as Data Message when your app is in background or is killed. In these Scenarios, if you want to retrieve your notification Message then you must define it in Key Value pair under
Advanced Option of FCM Console
and then retrieve this message by using this key in your activity which will be open by tabbing the Notification.
if (getIntent().getExtras() != null) {
Object value ;
for (String key : getIntent().getExtras().keySet()) {
if(key.equals("Message Key")) {
value = getIntent().getExtras().get(key); // value will represend your message body... Enjoy It
Log.d("NotificationTag" , key+"____" + value);
}
}
}
Just override the handleIntent() method of FirebaseMessagingService .class it will called in both foreground and background mode and here your can get and parse notification key and payload data
public void handleIntent(Intent intent)
{
String title = bundle.getString("gcm.notification.title");
String body = bundle.getString("gcm.notification.body");
}
Note: it will worked for play service 11
Related
I'm using FirebaseMessagingService for my push notifications. It is working as intented in app. onMessageReceived is called, I can get notification title and body + data payload and send reaction depends on payload data to my Activity using LocalBroadcastManager.
But there is problem with background push notification. This will only show notification in background, but it is not created in onMessageReceived because this function cannot be called if app is in background.
According to documentation, data part of push notification is stored in extras and can be found when Activity is resumed. I have function for this already and its working. But problem is that I dont have title and message, because it was not send to onMessageReceived and I cannot catch this information.
Is there any way how to obtain it? Because I need to show it in my dialog window inside app. Push notification is not only text and title and it is not just information for user, but it will do some action.
Receiving notification title, body and payload in FirebaseMessagingService:
override fun onMessageReceived(msg: RemoteMessage?) {
val pNotification = msg?.notification
val payload = msg?.data
if (pNotification != null){
val ntitle = pNotification.title
val nMsg = pNotification.body
}
//working with payload - creating notification and Intent for LocalBroadcastmanager
}
Catching payload from extras inside onResume()
private fun maybeFindBackgroundPayload(extras: Bundle?){
if (extras != null){
extras.keySet().forEach { key->
val keyValue = extras[key]
App.log("BackgroundKeyValues: $keyValue")
if (key.equals("gcm.notification.body", ignoreCase = true) && keyValue != null){
...
//Working with payload data key value - dont have title and body
}
}
}
}
Unfortunately, it is not possible the way you want it to work.
If the push notification has a notification part in the payload and your app is in the background, onMessageReceived will never be called. The notification is automatically created and displayed by firebase. There is no way to intercept this and modify the notification or do any other operation for that matter. Your app will only get control once the notification is clicked.
When the app is in foreground, as you mentioned, onMessageReceived will always be called.
The only way to ensure that onMessageReceived is called in all situations(foreground, background and app killed) is to send a data-only payload from firebase. That is, remove the notification part of the firebase payload body and put the content(title,body etc) in the data part of the payload. And in your onMessageReceived assign this title, body etc to the notification you are creating.
Here is how your payload from firebase will need to be:
{
"registration_ids":[
"firebase_token"
],
"data":{
"body":"body of notification",
"title":"title of notification",
"otherdatakey":"otherdatavalue"
}
}
Then in your onMessageReceived function, you need to explicitly extract the title and body and assign it to the notification(along with any other operations you want to do of course):
#Override
public void onMessageReceived(RemoteMessage message) {
Map<String, String> dataMap = message.getData();
String title = dataMap.get("title");
String body = dataMap.get("body");
String otherdatavalue = dataMap.get("otherdatakey");
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle(title)
.setContentText(body)
.setContentIntent(pendingIntent);//To handle click of notification
}
I am using FCM in my project and when trying to test the incoming notifications with the firebase "compose notification" feature I am putting a title, a body and an image URL to the message and it shows what it should look like - a rich notification with image. But the notification that is being sent to me is a normal one without any image.
here is the firebase UI and what is suposed to happen -
My issue is that I am getting only the text, without the image.
here is my MyFirebaseMessagingService class -
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public static final String RECEIVED_FCM_ACTION = "com.onemdtalent.app.RECEIVED_FCM_ACTION";
public static final String BD_KEY_BODY = "BD_KEY_BODY";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
String image = remoteMessage.getData().get("image");
Timber.d("onMessageReceived: %s", remoteMessage.getFrom());
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
String body = remoteMessage.getNotification().getBody();
Timber.d("Message Notification Body: %s", body);
// broadcast
Intent localIntent = new Intent(RECEIVED_FCM_ACTION);
localIntent.putExtra(BD_KEY_BODY, image);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
}
}
As I sayed, I am getting only the text without the image. what am I missing?
Solved - I used an old version of firebase messaging dependency and I updated it, including my entire project to androidX and now I can see the images :)
can i intercept notifications when my app is closed?
I need for set badge with this library ShortcutBadger
Thanks.
There are 3 types of notifications:
notification: Can be send from the web console or any backend, it has predefines values. If the app is open the behaviour is customizable on onMessageRecieve if the app is closed triggers a default notification.
data: a key value pair, only Strings. Can be send from any backend. The behaviour is always defined in onMessageReceived method.
notification and data: Combination of previous it will have the behaviour of a notification, the data will be available as extras once the notification is clicked in the default launcher activity. Can be send from the web console or any backend.
A push is a json called Payload which contains those objects:
payload: {
data: {...}
}
Yes, you can send yourself a data type notification it will always do what you write in the onMessageReceived method inside the MessagingService.
This doc should help you
https://firebase.google.com/docs/cloud-messaging/concept-options?hl=es-419
If you dont have a server use Functions.
Since the default notification wont be shown, you will probably want to show your own.
If you want to also show a notification then the NotificationCompat class must be called from inside onMessageReceived. The visual notification is not related to the push message, in fact, a visual notification can be triggered by pressing a button.
For creating a visual notification, the best approach is to let Android Studio do it for you. Second click on the packages where your activities .java are, new, then selecet ui-component and there is the notification. It will create a basic template of a notification. Then use those methods inside onMessaReceived passing the info that has to be show to the user.
The docs about the class
https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html
And you will probably find this error
NotificationCompat.Builder deprecated in Android O
In case you never solved this, the problem is not how you are implementing it within your app, but how the JSON data payload is being sent. See this question and the respective answers for why you are not receiving the messages while they are in the background.
Very short summary is, if you are receiving the notification payload, it will never trigger in the background. If you receive the data payload without notification, you can parse and perform actions while the app is in the background.
do you mean it?
public class AppFcmMessagingsService extends FirebaseMessagingService {
private static final String TAG = "FirebaseMessageService";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
try {
if(remoteMessage.getData().size() > 0) {
final JSONObject jsonObject = new JSONObject(remoteMessage.getData().toString());
Log.d(TAG,"remoteMessage = " + jsonObject.toString());
int badgeCount = 1;
ShortcutBadger.applyCount(getApplicationContext(), badgeCount);
}
} catch (Exception e) {
Log.e(TAG, "onMessageReceived: ", e);
}
if(remoteMessage.getNotification() != null) {
int badgeCount = 1;
ShortcutBadger.applyCount(getApplicationContext(), badgeCount);
Log.d(TAG, "notification body : " + remoteMessage.getNotification().getBody());
}
}
}
The FirebaseMessagingService has the method onMessageReceived() which we should override to handle notifications, but this only works when the app is in Foreground.
To handle notifications even when the app is in background, I used to override the handleIntent, to just call the onMessageReceived().
In FirebaseMessagingService 11.6.0, the method handleIntent became final, with that said, I can't override it as I was doing.
How should I handle notifications when my app is in background in the 11.6.0?
public class NotificationsListenerService extends FirebaseMessagingService {
private static final String TAG = "NotificationsListenerService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage)
String notifyData = remoteMessage.getData().get("notifData");
if(notifyData.contains("|")){
String[] itens = notifyData.split("\\|");
notifyData = itens[0];
}
String notifyType = remoteMessage.getData().get("notifType");
String title = remoteMessage.getData().get("title");
String message = remoteMessage.getData().get("body");
if(!isAppInForeground(App.getContext())){
sendNotification(title, message, notifyData, notifyType);
}
}
#Override
public final void handleIntent(Intent intent) {
...
this.onMessageReceived(builder.build());
...
}
private void sendNotification(String messageTitle, String messageBody, String notifyData, String notifyType) {
...
}
//Detect if app is in foreground
private boolean isAppInForeground(Context context) {
...
}
}
It's not intended for anyone to override handleIntent(). That's why it was made final. Also, you'll notice that it's completely missing from the javadocs - that's intentional.
If you want to handle a message in any circumstance (both foreground and background), use onMessageReceived(). The javadoc for that method says:
Called when a message is received.
This is also called when a notification message is received while the
app is in the foreground. The notification parameters can be retrieved
with getNotification().
This should work for data messages, but not notification messages sent from the console. Notification messages have different delivery behavior. See the documentation about message types and how to handle them.
I'd add that in FirebaseMessagingService 11.8.0 docs, it is stated in https://firebase.google.com/docs/cloud-messaging/android/receive that if a notification has a data payload it will call onMessageRecieved() when the app is in the foreground, and if the app is in the background the notification and data payload are delivered in the extras of the intent of your launcher Activity.
So, this means you need to decide how to handle the notification in two places, depending on whether the user is actively using the app or if it is in the background.
As you have seen yourself, if you receive the notification while the app is in the foreground, onMessageReceived() is called and you handle the notification there.
When the app is launched from the background, you have 2 options:
1: By default, the notification is sent to your system tray, and when it is clicked it opens your main activity, passing the data (what would have been remoteMessage.getData() in onMessageReceived()) to your activity as intent extras. You can handle the extras in your main activity like so and decide what to do with them, for instance check for a key value and launch a related intent.
// [START handle_data_extras]
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d(TAG, "Key: " + key + " Value: " + value);
}
}
You can decide what intent to open on-click if you add an intent-filter in your app manifest and a designated "click_action" value in your notification, and then handle the intent extras in the designated activity. See https://stackoverflow.com/a/39665485/3746204
I'd also suggest checking the firebase messaging sample app for ideas: https://github.com/firebase/quickstart-android/tree/master/messaging
i have the same problem after update firebase library version.
i think the easiest way is downgrade firebase library again (i use 11.4.2) and handleIntent() still works !
I am using Firebas mesaging service class. and Its working properly when app is running in foreground but when i clear this application from recent i am not able to access the push notification data for setting it on textview.
I want to store data in database when app is running in background.
I had Used Database to store the value directly but its not working.
public void onMessageReceived(RemoteMessage message) {
database=new SQLiteHelper(getApplicationContext());
database.open();
String image = message.getNotification().getIcon();
String title = message.getNotification().getTitle();
String text = message.getNotification().getBody();
String sound = message.getNotification().getSound();
int id = 0;
database.addQuotes(text,"Xyz");
}
In MainActivity.java in Oncreate method
Bundle extras = getIntent().getExtras();
if (extras != null) {
final String message = extras.getString("message");
quote_text.setText(message);
Toast.makeText(this, "A", Toast.LENGTH_SHORT).show();
}
But message shows null data.
based on this:
I want to store data in database when app is running in background
The service calls which extends FirebaseMessagingService has a method called onMessageReceived which is called when a push notification is received on the front-end (app) add your message to DB there!
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
.....
// parse and add your message to Db here!
Normally when your app is in the background, Android directs notification messages to the system tray. A user tap on the notification opens the app launcher by default.
This includes messages that contain both notification and data payload (and all messages sent from the Notifications console). In these cases, the notification is delivered to the device's system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
But you can refer this answer on stackoverflow if you want to get notification data-messages in your app while in background.
You may also refer this