14

I've implemented Firebase in my app and I'm sending push with extra data. When my app is in foreground I'm handling data properly and showing my own notification, but I have a problem with fetching data, when Firebase shows Notification "automatically" when app was "homed" (not killed). According DOCS Activity should get new Intent with extras fulfilled with my values, instead app just get back to front, old state is restored.

Scenario:

  1. opening app, pressing Home
  2. sending push through Firebase console, Firebase is creating Notification WITHOUT calling onMessageReceived (according to table in docs, it should?)
  3. when user pick notification app will be brought to front in same state as was "homed", and Intent is fulfilled with "original" extras used for open Activity on top

I have logs in onCreate, onNewIntent, onResume (Activity) and in onMessageReceived (Service), only onResume is called, in which I'm printing extras like below:

if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("Activity onResume", "Key: " + key + " Value: " + value);
        }
    }
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
snachmsm
  • 17,866
  • 3
  • 32
  • 74

4 Answers4

6

Messages with both notification and data payload, both background and foreground. In this case the data payload is delivered to extras of the intent of your launcher activity. If you want to get it on some other activity, you have to define click_action on the data payload. So get the intent extra in your launcher activity.

Edit:-

From the documentation :- 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.

So check the launcher activity's oncreate() method with getIntent() extras upon click of notification.

Nainal
  • 1,728
  • 14
  • 27
  • If my app is killed then data is delivered to launchers activity, thats true. I'm talking about situation when app is already opened, then it get back to front on last `Activity` and launcher `Activity` isn't called/opened – snachmsm Aug 24 '18 at 10:03
  • 1
    Firebase will call launcher activity getIntent() part also, in case when app is in background. Are you getting notification when app is in background? – Nainal Aug 24 '18 at 10:07
  • 2
    If you are getting notification, then click on the notification and check if on click of notification whether launcher activity's getIntent is called? – Nainal Aug 24 '18 at 10:23
  • YES, yes it is! "who" is calling this method, how to handle this? launcher `Activity` isn't starting, it isn't even on activies stack in my case (launcher is only splashscreen). I think overriding `getIntent()` and fetching my data there isn't a good idea... (also its get called twice) – snachmsm Aug 24 '18 at 10:28
  • FCM will call this, put a log inside the oncreate method of splashScreen under your code:- if (getIntent().getExtras() != null).... – Nainal Aug 24 '18 at 10:30
  • not working to me, even i define click_action, press home, get notification -> it bring app to current state, i can not get notification data – famfamfam May 06 '19 at 08:21
  • lol. found problem, my MainScreen is set laughMode = single top?, remove this line then got data – famfamfam May 06 '19 at 08:23
6

So I was looking for this answer and read the same. It has to be some where. I know this is a year old but they still haven't really made it clear. In the pendingActivity associated with the notification ( in my case it was MainActivity ) I added the following. Please note I was working through the Google Codelabs com.example.android.eggtimernotifications not that this was in the answers.

    override fun onResume() {
        super.onResume()
        intent?.run {
            val keys = this.extras?.keySet()
            if (!keys.isNullOrEmpty()) {
                keys.forEach { key ->
                    when (this.extras!![key]) {
                        is Long -> println("$key = ${this.getLongExtra(key, 0L)}")
                        is Int -> println("$key = ${this.getIntExtra(key, 0)}")
                        is String -> println("$key = ${this.getStringExtra(key)}")
                        is Boolean -> println("$key = ${this.getBooleanExtra(key, false)}")
                        else -> println("unkonwn Type")
                    }
                }
            }
        }
    }

This resulted in the following.

  • I/System.out: google.delivered_priority = high
  • I/System.out: google.sent_time = 1585284914411
  • I/System.out: google.ttl = 2419200
  • I/System.out: google.original_priority = high
  • I/System.out: cereal = Shreddies
  • I/System.out: from = /topics/breakfast
  • I/System.out: milk = 1 cup
  • I/System.out: sugar = none
  • I/System.out: google.message_id = 0:1585284914700957%f6ddf818f6ddf818
  • I/System.out: collapse_key = com.example.android.eggtimernotifications

The data keys were cereal, from, milk and sugar.

Gary Robottom
  • 101
  • 1
  • 5
2

onMessageReceived() is not called when application is on background. I have this problem few months a ago. I resolve it by override handlerIntent method. But your firebase messaging library should

implementation 'com.google.firebase:firebase-messaging:10.2.1'

after that:

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

                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);
        }
    }

if you don't want to downgrade your library then

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 https://firebase.google.com/docs/cloud-messaging/android/receive#sample-receive

Erselan Khan
  • 692
  • 6
  • 13
  • current Firebase version is 17 (I'm using 17.1.+) and I won't downgrade this lib, especially so much, so it isn't a solution. In current version we can't override `handleIntent` – snachmsm Aug 24 '18 at 09:50
  • I know few person wouldn't prefer to downgrade library that's why I already mention solution for latest version too – Erselan Khan Aug 24 '18 at 17:51
1

According to documentation Cloud messaging docs message can be delivered in 3 states:

  1. Notification
  2. Data
  3. Notification & Data

Background handling:

For 2. onMessageReceived will be called without UI and additional handling. Later you can show something custom.

When it comes to 3. android will show notification and hold data until there is user interaction. After click it's just resuming your existing activity. Your onNewIntent is not triggered because your launch mode is not FLAG_ACTIVITY_SINGLE_TOP.

You should also check your logcat output for: Google Play services out of date.

3mpty
  • 1,354
  • 8
  • 16
  • using Firebase console I can send only Notification or Notification & Data push. I have to use second one for custom params. When app was "homed", still alive in background, `onMessageReceived ` isn't called at all (both at the moment of receiving push and when notification is pressed) – snachmsm Aug 24 '18 at 09:47
  • @snachmsm it's not possible to send data only message from console. From documentation: `In a trusted environment such as Cloud Functions or your app server, use the Admin SDK or the FCM Server Protocols: Set the data key only. ` – 3mpty Aug 24 '18 at 09:51
  • thats not true, last section in sending-push-form called "Advanced settings" (or options, I have localized console) lets you add custom key-value params. I'm getting them without a problem, when app is in foreground or is killed – snachmsm Aug 24 '18 at 10:05
  • Console allows you to send text and optionally data. But you cannot send data only message from console. That is the difference. – 3mpty Aug 24 '18 at 10:18
  • thats true, but it is not resolving my problem... I need extra data, so I have to handle it by myself dealing with autoshowing `Notification`, which is carrying my fields. Problem is that I can't fetch my key-value pairs in scenario described in question... – snachmsm Aug 24 '18 at 10:23
  • you are right, remove laughMode=singleTop in androidmanifet then it work – famfamfam May 06 '19 at 08:25