273

I'm working with Firebase and testing sending notifications to my app from my server while the app is in the background. The notification is sent successfully, it even appears on the notification centre of the device, but when the notification appears or even if I click on it, the onMessageReceived method inside my FCMessagingService is never called.

When I tested this while my app was in the foreground, the onMessageReceived method was called and everything worked fine. The problem occurs when the app is running in the background.

Is this intended behaviour, or is there a way I can fix this?

Here is my FBMessagingService:

import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}
Frank van Puffelen
  • 418,229
  • 62
  • 649
  • 645
Cyogenos
  • 2,989
  • 2
  • 13
  • 13
  • In addition to the json body, where is your [onTokenRefresh](https://firebase.google.com/docs/cloud-messaging/downstream#access-the-registration-token_1) code? Have you completed the [Android setup](https://firebase.google.com/docs/cloud-messaging/android/client#set-up-firebase-and-the-fcm-sdk)? – Kato May 21 '16 at 05:22
  • 4
    What do you mean the json body of the notification? Also, my onTokenRefresh code is inside my FirebaseInstanceID service. – Cyogenos May 21 '16 at 16:37
  • Can you post the sample payload you are sending? – AL. May 23 '16 at 07:57
  • use https://istudy.io/android-push-notifications-using-firebase-fcm/ – YasirSE Jul 25 '16 at 12:10
  • You can also check this thread http://stackoverflow.com/questions/39046270/google-fcm-getintent-dont-returning-expected-data-when-app-is-in-background-stat – Md. Sajedul Karim Aug 27 '16 at 09:24
  • There are two types of FCM .http://stackoverflow.com/a/37845174/3496570 – AndroidGeek Sep 20 '16 at 04:48
  • I have everything explained in detail here: https://stackoverflow.com/questions/45671869/firebase-onmessagereceived-not-called/45673611#45673611 – JacksOnF1re Jan 08 '19 at 09:20
  • I have that same problem [firebase-messaging-service-not-received-when-app-closed](https://stackoverflow.com/questions/58178693/firebase-messaging-service-not-received-when-app-closed?noredirect=1#comment102739708_58178693) – yhackup Oct 01 '19 at 11:59
  • https://stackoverflow.com/questions/37711082/how-to-handle-notification-when-app-in-background-in-firebase – adarsh Feb 28 '20 at 13:00

27 Answers27

166

This is working as intended, notification messages are delivered to your onMessageReceived callback only when your app is in the foreground. If your app is in the background or closed then a notification message is shown in the notification center, and any data from that message is passed to the intent that is launched as a result of the user tapping on the notification.

You can specify a click_action to indicate the intent that should be launched when the notification is tapped by the user. The main activity is used if no click_action is specified.

When the intent is launched you can use the

getIntent().getExtras();

to retrieve a Set that would include any data sent along with the notification message.

For more on notification message see docs.

János
  • 27,206
  • 24
  • 130
  • 270
Arthur Thompson
  • 8,335
  • 3
  • 26
  • 31
  • 7
    Is there a way to set the `click_action` when I'm using the Firebase Notification Console? – Nii Laryea May 31 '16 at 01:28
  • 7
    ok, but what if the app is killed (no foreground or background)? – michalu Jun 15 '16 at 12:15
  • 1
    You can test it for yourself. Send a message while your app isn't running. The message should still be delivered to the target phone. – Cyogenos Jul 07 '16 at 01:19
  • Click action? from the system tray notification? thats is created by the system... u cannot include pending intent o anything that happends when you click. Do you? In this case? where the notification was made by the system itself. – superUser Aug 13 '16 at 13:24
  • When you are sending notification messages form the REST API you can specify a click_action that determines which intent is fired when the notification (if generated) is tapped by the user. See the REST API reference docs for more: https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support – Arthur Thompson Aug 13 '16 at 19:01
  • 4
    But how to disable user discard notification? Because if user discard it, it means that all data will be skip... Right? – Aleksey Timoshchenko Sep 01 '16 at 15:33
  • 4
    Correct! So when sending notification messages to Android, the accompanying data should be data that is enhancing the notification experience. It should not be app critical data, use data messages for data that the application needs even if the user dismisses the notification. – Arthur Thompson Sep 02 '16 at 22:49
  • but still can not get when message is received when app in background. – Mahdi Feb 27 '17 at 07:15
  • 8
    This is not entirely correct. If the message does only contain a data and not a notification payload, the message will ALWAYS be delivered to onMessageReceive, if the app is in foreground or not. – JacksOnF1re Aug 15 '17 at 08:42
  • https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages – JacksOnF1re Aug 15 '17 at 08:44
  • extra data not parsing when application close and starting an activity by tapping on notification – JosephM Sep 07 '17 at 07:48
  • I'm using data message (without notification {}). But still, when the app is in background, only clicking the notification tray delivers the data payload in the app. If the message is dismissed by the user, the data never reaches. – Tahniat Ashraf Jan 22 '18 at 06:31
  • @ArthurThompson In oreo when app killed, onMessageReceived is not getting called. i just have payload with data only. any update do you have ? – Samir Mangroliya Feb 27 '18 at 12:47
  • @ArthurThompson sir could you please check [this question](https://stackoverflow.com/q/49902190/8027365) regarding **fcm push notification** – anonymous Apr 18 '18 at 14:25
  • Hi! I tried use `getIntent().getExtras();` but why always return null? – E-Place May 03 '18 at 12:04
  • 2
    Don't send notification! Send data only and enclose fields `title` and `message` inside. In this case `onMessageReceived()` will be called on opened and closed app. You'll build a custom notification and translate it using BroadcastReceiver. Full control over any notification in every app state in this case. – Zon Oct 23 '18 at 09:39
  • can you provide the code for link for Opening the targetActivity when the app is backgroung. I tried using "click_action" in the payload but it did not work – Rohit Singh Jan 15 '19 at 18:49
  • try https://stackoverflow.com/questions/37711082/how-to-handle-notification-when-app-in-background-in-firebase – Vivek Pratap Singh Feb 25 '19 at 11:55
  • Hi @János, I am facing with issue when my app is in background and if notification title is blank in that case in the Notification tray its displaying App Name by default. How to resolve please suggest – Fusioni Technologies Apr 13 '20 at 11:46
  • @all Facing same issue when app is in killed state onMessageReceived not getting called and not able to perform action in that state. I am having data payload already in that. Anyone having solution to this ? – Jay Rathod RJ Sep 02 '20 at 07:41
  • added blog base on @JacksOnF1re, check out https://codingwithtashi.medium.com/firebase-onmessagereceived-not-called-when-app-in-background-18e78280c6cb – codingwithtashi Mar 20 '21 at 18:15
145

Remove notification field completely from your server request. Send only data and handle it in onMessageReceived() otherwise your onMessageReceived() will not be triggered when app is in background or killed.

Don't forget to include "priority": "high" field in your notification request. According to the documentation: data messages are sent with a normal priority, thus they will not arrive instantly; it could also be the problem.

Here is what I am sending from server

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}

So you can receive your data in onMessageReceived(RemoteMessage message) like this....let say I have to get id

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }
Zohab Ali
  • 4,958
  • 3
  • 31
  • 43
  • 10
    I found that if i send only data message, Then App which is cleared from task manager will not be able to get notification.Is this an intended behavior? – Prabhjot Singh Dec 28 '16 at 06:26
  • 2
    This was the solution for me to receive messages in the background! – Ray Hulha Jan 10 '17 at 15:01
  • Does this mean that in the console we can't handle the notification data and if we send a pure HTTP request without the notification section then we can handle notification data ? I started to use Firebase Console expecting I could do this, so I am moving back to HTTP POST notification :-( – Javier Delgado Apr 19 '17 at 22:06
  • Hi, how to show badge on app icon, when app in background. – Avinash May 24 '17 at 07:28
  • 7
    In Oreo when app killed, onMessageReceived is not getting called. i just have payload with data only. any update do you have ? – Samir Mangroliya Feb 27 '18 at 12:47
  • @SamirMangroliya I had the same problem. Add `"priority": "high"` to your request. Because data messages are sent with a normal priority, they don't arrive instantly. – itachi May 28 '18 at 11:49
  • 2
    Works like a charm! – ssk Jun 30 '18 at 01:27
  • 3
    Love you alot for this answer :p – Ahmad Arslan Aug 30 '18 at 12:07
  • 1
    Works great! Thanks –  Oct 08 '18 at 10:55
  • 1
    Hi, But when the app is totally closed it does not work – C Williams Aug 12 '19 at 19:52
  • I'm trying to reproduce the scene in my flutter app. This didn't work for me. Can you suggest anything on flutter. Thanks in advance – Chandu Jan 09 '20 at 16:41
  • 1
    This Works. Tested on Android 9.0 – manna Jan 25 '20 at 10:56
  • I had code in onCreate of Application that was crashing if app was killed and I received notification. Also found out that right directly after you kill the app after running it android studio, you don't receive notification. I opened the app again and killed it again and received notifications. Weird. – coolcool1994 Aug 24 '20 at 21:19
  • seriously man loves you. You did a really great job. I'm very happy – Debashis Nandy Oct 28 '20 at 12:46
  • This worked for me after 1 day search – Neo Dec 21 '20 at 05:40
66

this method handleIntent() has been depreciated, so handling a notification can be done as below:

  1. Foreground State: The click of the notification will go to the pending Intent's activity which you are providing while creating a notification pro-grammatically as it generally created with data payload of the notification.

  2. Background/Killed State - Here, the system itself creates a notification based on notification payload and clicking on that notification will take you to the launcher activity of the application where you can easily fetch Intent data in any of your life-cycle methods.

manas.abrol
  • 799
  • 7
  • 5
35

Here is more clear concepts about firebase message. I found it from their support team.

Firebase has three message types:

Notification messages : Notification message works on background or foreground. When app is in background, Notification messages are delivered to the system tray. If the app is in the foreground, messages are handled by onMessageReceived() or didReceiveRemoteNotification callbacks. These are essentially what is referred to as Display messages.

Data messages: On Android platform, data message can work on background and foreground. The data message will be handled by onMessageReceived(). A platform specific note here would be: On Android, the data payload can be retrieved in the Intent used to launch your activity. To elaborate, if you have "click_action":"launch_Activity_1", you can retrieve this intent through getIntent() from only Activity_1.

Messages with both notification and data payloads: When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification. When in the foreground, your app receives a message object with both payloads available. Secondly, the click_action parameter is often used in notification payload and not in data payload. If used inside data payload, this parameter would be treated as custom key-value pair and therefore you would need to implement custom logic for it to work as intended.

Also, I recommend you to use onMessageReceived method (see Data message) to extract the data bundle. From your logic, I checked the bundle object and haven't found expected data content. Here is a reference to a similar case which might provide more clarity.

From server side, firebase notification should bellow format:

Server side should send "notification" object. Lacks of "notification" object in my TargetActivity didn't getting message using getIntent().

Correct message format is given bellow:

{
 "data": {
  "body": "here is body",
  "title": "Title"
 },
"notification": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
 "to": "ffEseX6vwcM:APA91bF8m7wOF MY FCM ID 07j1aPUb"
}

Here is more clear concepts about firebase message. I found it from their support team.

For more info visit my this thread and this thread

Md. Sajedul Karim
  • 6,263
  • 3
  • 47
  • 77
  • 4
    worth mentioning that "data messages" will not be received if the device is in deep doze mode (introduced in Android 7.0). be careful with those! – Sameer J Feb 21 '19 at 21:03
30

I had the same problem. It is easier to use the 'data message' instead of the 'notification'. The data message always load the class onMessageReceived.

In that class you can make your own notification with the notificationbuilder.

Example:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0 /* request code */, intent,PendingIntent.FLAG_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
Koot
  • 397
  • 2
  • 5
  • 7
    Thanks ..I changed my server code and use "data" instead of "notification" and now it's working perfect, – Mahesh Kavathiya Jun 02 '16 at 05:40
  • 5
    @Koot it working only if app is in foreground not if it is in background. can u help me to trigger this event in both cases?? – Anant Shah Jul 16 '16 at 06:09
  • @AnantShah how does your POST to the Firebase server looks like? – Koot Jul 23 '16 at 10:01
  • 3
    There are actually three possible cases here. 1) App in foreground. 2) App in background. 3) App not running. As you say, a 'data' message will be received in the first two cases, but *not* in the third case, when the app is not running. To cater for all three cases, you need to set the 'notification' field in the message. (Also a good idea if you want to support iOS as well as Android clients) – Steve Moseley Aug 26 '16 at 02:29
  • @SteveMoseley Do you have a link to the documentation where these three cases are described? I always only see "foreground" and "background" mentioned in the docs and thought that background included case "app is not running" - because they advertise like this "send notifications to reengage your users so they use your app again and you make money" – Micha F. Aug 26 '16 at 18:08
  • 1
    Even in the app is not running, i stil get a message from the server on the function onmessagereceived. I agree with you that it is better to use 'notification' if you want to support ios too. – Koot Aug 27 '16 at 07:20
  • thank..! I am passing 3 values from backend how to Handel the frontend side – Manideep Feb 25 '20 at 12:01
24

As per Firebase Cloud Messaging documentation-If Activity is in foreground then onMessageReceived will get called. If Activity is in background or closed then notification message is shown in the notification center for app launcher activity. You can call your customized activity on click of notification if your app is in background by calling rest service api for firebase messaging as:

URL-https://fcm.googleapis.com/fcm/send

Method Type- POST

Header- Content-Type:application/json
Authorization:key=your api key

Body/Payload:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

And with this in your app you can add below code in your activity to be called:

<intent-filter>
                <action android:name="OPEN_ACTIVITY_1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
Ankit Adlakha
  • 1,228
  • 9
  • 14
  • Where would I create the intent and have it open a specific activity? I know this registers the OPEN_ACTIVITY_1 intent in the manifest, but where do I actually call it? – Cyogenos Jun 03 '16 at 16:22
  • 1
    Check this: https://firebase.google.com/docs/cloud-messaging/downstream#sample-receive – Ankit Adlakha Jun 06 '16 at 16:16
  • Should we call an activity from intent-filters? Or start it manually in `onMessageReceived`? – CoolMind Jun 25 '19 at 08:05
16

onMessageReceived(RemoteMessage remoteMessage) method called based on the following cases.

  • FCM Response With notification and data block:
{
  
"to": "device token list",
  "notification": {
    "body": "Body of Your Notification",
    "title": "Title of Your Notification"
  },
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}
  1. App in Foreground:

onMessageReceived(RemoteMessage remoteMessage) called, shows LargeIcon and BigPicture in the notification bar. We can read the content from both notification and data block

  1. App in Background:

onMessageReceived(RemoteMessage remoteMessage) not called, system tray will receive the message and read body and title from notification block and shows default message and title in the notification bar.

  • FCM Response With only data block:

In this case, removing notification blocks from json

{
  
"to": "device token list",
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}

Solution for calling onMessageReceived()

  1. App in Foreground:

onMessageReceived(RemoteMessage remoteMessage) called, shows LargeIcon and BigPicture in the notification bar. We can read the content from both notification and data block

  1. App in Background:

onMessageReceived(RemoteMessage remoteMessage) called, system tray will not receive the message because of notification key is not in the response. Shows LargeIcon and BigPicture in the notification bar

Code

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

    Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

Reference Link:

https://firebase.google.com/docs/cloud-messaging/android/receive

vishnuc156
  • 1,166
  • 12
  • 10
  • Most important part for people suffering from background issue is to remove the "notification" property from JSON being sent by the server. this solves the problem. Thanks a lot. – Ramy M. Mousa Apr 21 '20 at 21:46
12

If app is in the background mode or inactive(killed), and you click on Notification, you should check for the payload in LaunchScreen(in my case launch screen is MainActivity.java).

So in MainActivity.java on onCreate check for Extras:

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }
Gent Berani
  • 5,297
  • 1
  • 34
  • 39
12

I got the same issue. If the app is foreground - it triggers my background service where I can update my database based on the notification type. But, the app goes to the background - the default notification service will be taken care to show the notification to the user.

Here is my solution to identify app in background and trigger your background service,

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

In the manifest.xml

<receiver android:exported="true" android:name=".FirebaseBackgroundService" android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>

Tested this solution in latest android 8.0 version. Thanks

Nagendra Badiganti
  • 1,566
  • 2
  • 18
  • 28
  • whare to use this FirebaseBackgroundService class?? @Nagendra Badiganti –  Nov 22 '17 at 06:48
  • where to use this code public class FirebaseBackgroundService extends WakefulBroadcastReceiver @Nagendra Badiganti –  Nov 22 '17 at 07:17
  • create a service class in your package and register in your manifest.xml. Make sure that you have the filter for your notifications. Since the service triggers for every GCM notification. – Nagendra Badiganti Nov 22 '17 at 07:30
  • https://firebase.google.com/docs/cloud-messaging/android/receive#sample-receive i am following this link, i need to add this class to receive notification . just sending message from firebase first message.. it says completed but not receiving notification @Nagendra Badiganti –  Nov 22 '17 at 09:09
  • did you add google-services.json in your project root folder? – Nagendra Badiganti Nov 22 '17 at 13:54
  • Thanks for this answer ! I don't see the chapter on this subject in the firebase link, is there any ? Could you please include your BackgroundSyncJobService class in your answer ? – matdev Jan 15 '18 at 11:28
  • 1
    `WakefulBroadcastReceiver` is deprecated since API level 26.1.0. – Minoru Feb 22 '18 at 15:50
6

Override the handleIntent Method of the FirebaseMessageService works for me.

here the code in C# (Xamarin)

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

and thats the Code in Java

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}
t3h Exi
  • 353
  • 3
  • 7
5

By default the Launcher Activity in you app will be launched when your app is in background and you click the notification, if you have any data part with your notifcation you can handle it in the same activity as follows,

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}
Uzair
  • 1,413
  • 13
  • 16
  • If I navigate from mainActivity, how navigate back to particular Activity will work? – Mac_Play Mar 11 '18 at 14:16
  • @Uzair getIntent().getExtras() always getting null,Do you have any other solution ?When app is going bacground onMessageReceived method not call – Komal12 Mar 28 '19 at 03:41
3

If app is in background Fire-base by default handling notification But if we want to our custom notification than we have to change our server side, which is responsible for to send our custom data(data payload)

Remove notification payload completely from your server request. Send only Data and handle it in onMessageReceived() otherwise your onMessageReceived will not be triggered when app is in background or killed.

now,your server side code format look like,

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

NOTE: see this line in above code
"text": "John Doe shared a contact in the group Contact Exchange" in Data payload you should use "text" parameter instead of "body" or "message" parameters for message description or whatever you want to use text.

onMessageReceived()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }
Hiren
  • 1,511
  • 11
  • 14
2

Just call this in your MainActivity's onCreate Method :

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }
Aman Shekhar
  • 2,470
  • 16
  • 27
2

according to the solution from t3h Exi i would like to post the clean code here. Just put it into MyFirebaseMessagingService and everything works fine if the app is in background mode. You need at least to compile com.google.firebase:firebase-messaging:10.2.1

 @Override
public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }



           onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}
Frank
  • 2,168
  • 2
  • 10
  • 16
  • I'm trying to implement your solution, but the handleIntent() method is final in my SDK version (SDK 27), so I cannot override it in my service... – matdev Jan 15 '18 at 11:17
  • Yes but thats not my fault or any reason to give -1 !!! Very arrogant. It works until firebase 11.4.2 then google changed it (made this method final). So now you must program your own solution with notification. – Frank Jan 18 '18 at 20:09
  • I did not give a -1 but a +1 ! – matdev Jan 18 '18 at 21:57
  • You save my job :P – Amitabha Biswas Feb 26 '18 at 08:09
1

I had this issue(app doesn't want to open on notification click if app is in background or closed), and the problem was an invalid click_action in notification body, try removing or changing it to something valid.

Octavian Lari
  • 81
  • 2
  • 9
1

The point which deserves highlighting is that you have to use data message - data key only - to get onMessageReceived handler called even when the app is in background. You shouldn't have any other notification message key in your payload, otherwise the handler won't get triggered if the app is in background.

It is mentioned (but not so emphasized in FCM documentation) here:

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

Use your app server and FCM server API: Set the data key only. Can be either collapsible or non-collapsible.

YNG
  • 732
  • 1
  • 10
  • 15
1

The backend I'm working with is using Notification messages and not Data messages. So after reading all the answers I tried to retrieve the extras from the bundle of the intent that comes to the launched activity. But no matter which keys I tried to retrieve from getIntent().getExtras();, the value was always null.

However, I finally found a way to send data using Notification messages and retrieve it from the intent.

The key here is to add the data payload to the Notification message.

Example:

{
    "data": {
        "message": "message_body",
        "title": "message_title"
    },
    "notification": {
        "body": "test body",
        "title": "test title"
    },
    "to": "E4An.."
}

After you do this, you will be able to get your info in this way:

intent.getExtras().getString("title") will be message_title

and intent.getExtras().getString("message") will be message_body

Reference

Vito Valov
  • 1,665
  • 1
  • 17
  • 34
1

If your problem is related to showing Big Image i.e. if you are sending push notification with an image from firebase console and it displays the image only if the app in the foreground. The solution for this problem is to send a push message with only data field. Something like this:

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }
Neha
  • 123
  • 6
Arun
  • 613
  • 1
  • 7
  • 14
  • you lost comma before "AnotherActivity". My android vibrates but really nothing shown (no text, no image, no push). – jekaby Jun 22 '17 at 09:41
1

Try this:

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            for (String key : intent.getExtras().keySet()) {
            builder.addData(key, intent.getExtras().get(key).toString());
        }
            onMessageReceived(builder.build());
        } else {
            super.handleIntent(intent);
        }
    } catch (Exception e) {
        super.handleIntent(intent);
    }
}
Ram Koti
  • 2,147
  • 6
  • 24
  • 34
1

When message is received and your app is in background the notification is sent to the extras intent of the main activity.

You can check the extra value in the oncreate() or onresume() function of the main activity.

You can check for the fields like data, table etc ( the one specified in the notification)

for example I sent using data as the key

public void onResume(){
    super.onResume();
    if (getIntent().getStringExtra("data")!=null){
            fromnotification=true;
            Intent i = new Intent(MainActivity.this, Activity2.class);
            i.putExtra("notification","notification");
            startActivity(i);
        }

}
Sanjeev S
  • 913
  • 1
  • 12
  • 26
1

I had similar issue. Based on the answers and references mentioned in this page, here are my two cents on how I resolved my problem with the below approach:

The message format I had earlier was as below:

    {
  "notification": {
    "title": "AppName",
    "sound": null,
    "body": "Hey!YouhaveaMessage"
  },
  "data": {
    "param1": null,
    "param2": [
      238
    ],
    "id": 1
  },
  "to": "--the device push token here--"
}

I modified the message format to the below:

    {
  "data": {
    "title": "AppName",
    "body": "Hey! You have a message",
    "param1": null,
    "param2": [
      238
    ],
    "id": 1
  },
  "priority": "high",
  "to": " — device push token here — "
}

Then I retrieved the title, body and all the parameters from the "data" payload itself. This solved the problem and I could then get the OnMessageReceived callback even though the app is in the background. I wrote a blog post explaining the same issue, you can find it here.

Neeraja Gandla
  • 45
  • 2
  • 13
0

I was having the same issue and did some more digging on this. When the app is in the background, a notification message is sent to the system tray, BUT a data message is sent to onMessageReceived()
See https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
and https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

To ensure that the message you are sending, the docs say, "Use your app server and FCM server API: Set the data key only. Can be either collapsible or non-collapsible."
See https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

Eric B.
  • 564
  • 9
  • 16
0

There are two types of messages: notification messages and data messages. If you only send data message, that is without notification object in your message string. It would be invoked when your app in background.

Shongsu
  • 933
  • 1
  • 10
  • 22
0

Check the answer of @Mahesh Kavathiya. For my case, in server code has only like this:

{
"notification": {
  "body": "here is body",
  "title": "Title",
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

You need to change to:

{
 "data": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
"notification": {
  "body": "here is body",
  "title": "Title"
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

Then, in case app in Background, the default activity intent extra will get "data"

Good luck!

Huy Nguyen
  • 545
  • 4
  • 16
0

you can try this in your main Activity , when in the background

   if (getIntent().getExtras() != null) {
            for (String key : getIntent().getExtras().keySet()) {
                Object value = getIntent().getExtras().get(key);
                Log.d(TAG, "Key: " + key + " Value: " + value);
            }
        }

Check the following project as reference

Mohamed El Shenawy
  • 688
  • 1
  • 9
  • 21
-1

Just override the OnCreate method of FirebaseMessagingService. It is called when your app is in background:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}
Renzo Ciot
  • 3,520
  • 2
  • 22
  • 28
  • This answer could be more useful if you could add an explanation, and link to some documentation. Can you please tell us how this is supposed to help? – kilokahn Jul 02 '18 at 19:19
  • @kilokahn Can you explain to me what you do you not understand? the indicated method must be inserted in the code that is part of the question and fully answers the question. The code is for Xamarin, but you can simply convert in java. – Renzo Ciot Jul 04 '18 at 15:50
  • AFAIK The official documentation (https://firebase.google.com/docs/cloud-messaging/android/client) does not talk about overriding OnCreate in a service extending FirebaseMessagingService - if you have access to documentation that does, perhaps you can share a link? Also, from your answer, it is not clear how overriding onCreate solves the problem of onMessageReceived not getting called when the notification is clicked - hence the request for more information. – kilokahn Jul 05 '18 at 00:31
  • The documentation does not mention the override of the OnCreate method, but it works because I'm using it in production. The code that you would like to insert in the onMessageReceived method and which obviously serves to do some background operations can be performed on OnCreate. – Renzo Ciot Jul 05 '18 at 06:46
  • In that case, elaborating on the fact that it somehow worked for you may prove more helpful than just listing the solution. Also, undocumented behaviour is likely to arbitrarily stop working with updates, and someone using them has to be prepared to rework their code when it does. This disclaimer needs to be put in. – kilokahn Jul 05 '18 at 19:52
-1

There are 2 types of Firebase push-notifications:

1- Notification message(Display message) -> -- 1.1 If you choose this variant, the OS will create it self a notification if app is in Background and will pass the data in the intent. Then it's up to the client to handle this data.

-- 1.2 If the app is in Foreground then the notification it will be received via callback-function in the FirebaseMessagingService and it's up to the client to handle it.

2- Data messages(up to 4k data) -> These messages are used to send only data to the client(silently) and it's up to the client to handle it for both cases background/foreground via callback-function in FirebaseMessagingService

This is according official docs:https://firebase.google.com/docs/cloud-messaging/concept-options

Balflear
  • 668
  • 1
  • 7
  • 20