evollu / react-native-fcm

react native module for firebase cloud messaging and local notification
MIT License
1.73k stars 681 forks source link

Not getting notification via FCM.on or FCM.getInitialNotification #771

Open bhosle-git opened 6 years ago

bhosle-git commented 6 years ago

Hi,

I'm seeing similar issue reported in https://github.com/evollu/react-native-fcm/issues/569, but not sure if it is exactly the same.. In some cases, when i click on the notification toast, i get the notification properly in my app in the FCM.on callback that i have as follows:

FCM.on(FCMEvent.Notification, async (notif) => {
    logger.log("received notification: " + JSON.stringify(notif))
    handleNotification(notif)  // my code to handle the notification
}

However, in one particular case, the above code doesn't get invoked. This is when I wait for a long time (say, 15+ minutes) before I click/tap on the notification toast. I think Android puts the app to sleep after that much time?

I am also already checking for FCM.getInitialNotification as follows.. (the code below is invoked from one of my componentDidMount methods)..

FCM.getInitialNotification().then(notif => {
    if(notif){
        logger.log('Got initial notificaton: ' + JSON.stringify(notif))
        NotificationUtil.handleNotification(notif)
    }
}

I do get something in the above block (initial notification), but its kind of empty. the log statement above is:

Got initial notificaton: {"opened_from_tray":1,"fcm":{"action":null}}

And this happens only when I wait for a while before i click/tap on the notification toast (not sure if some folks here are calling that a 'banner' - which is available when you swipe/pull down from the top of the phone screen)..

If the app is just minimized, and i tap on the notification toast in a couple of minutes, everything works fine - my FCM.on callback gets invoked, and i get the complete notification data as expected.. here's one log for the success case:

received notification: {"fcm":{"action":"my_test_action"},"show_in_foreground":true,"data.foo":"bar","sound":"default","opened_from_tray":1,"click_action":"my_test_action","priority":"high","id":"my_notif_id","body":"test notif body","title":"test notif title","icon":"ic_launcher","local_notification":true}

@evollu - do you know what could be causing this?

Thanks Amit

When openning an issue, please include following information for better support

  1. What version of RN and react-native-fcm are you running? "react": "^16.2.0", "react-native": "^0.51.0", "react-native-fcm": "^11.3.1",

  2. What device are you using? (e.g iOS9 emulator, Android 6 device)? Android 7.1.1 emulator (same behavior on many other versions, as well as my Samsung s8+ running 7.1.1)..

  3. Is your app running in foreground, background or not running? not running

Before openning an issue

  1. Reproduce it with the example project in this repo.
  2. If you can't receive iOS notification, make sure you can receive notification using quickstart-ios project provided by Firebase team
bhosle-git commented 6 years ago

quick update here..

i realized that we had upgraded the react-native-fcm version recently (11.3.1).. but when i rolled back to an earlier one (10.0.3), things work as expected!(double checked a few times rolling back/forward on these two versions, and that's what it looks like - regression in some version after 10.0.3)

evollu commented 6 years ago

one big change I've made is the local broadcasting. If you have chance can you test the latest version if this line is triggered? https://github.com/evollu/react-native-fcm/compare/v10.0.3...v11.3.1#diff-c04acb3238c7458755defae08932ece4R218

v10 has a big issue: if you have multiple app using this notif repo, both apps will get notifications

bhosle-git commented 6 years ago

can u double check the diff link? i can't see anything when i click on it.. (see attached screenshot) rn-fcm-diff

bhosle-git commented 6 years ago

btw, @evollu - I'm seeing another weird issue..

like already mentioned, i have registered the callbacks for FCM.on.. but i also check for FCM.getInitialNotification(..) from one of the componentDidMount methods (when my app loads)..

sometimes, the FCM.getInitialNotification(..) gets a pretty old (several hours) instance of a notification..

do you know what could cause that? when is the FCM.getInitialNotification(..) supposed to clear out? (or is there a way that I can clear that out from my app?)

is there any recommended pattern / best-practices so that I can know whether I should ignore the FCM.getInitialNotification(..) response or not?

Thanks..

RuairiOliver commented 6 years ago

I was dealing with a similar issue last week but everything seems to be working fine for me now. I was using wix react native navigation and that was causing problems that I didn't have with this library previously.

Now I get the initial notification before doing anything else on my application and store it to use once the user logs in to the app.

Also if the app starts by running react-native-run-android I'm not able to get the initial notification. If I kill the app and start it again after that everything is fine. This isn't a problem when it goes to a production release on the play store. It's just caused by the terminal starting my Main Intent it seems.

evollu commented 6 years ago

@bhosle-git the right url is https://github.com/evollu/react-native-fcm/compare/v10.0.3...v11.3.1

FCM.getInitialNotification(..) doesn't get updated until the app is killed. putting app in background for long time doesn't seems to kill the app. Usually you put some custom property in notification like type, then you just check if that thing is present in FCM.getInitialNotification. FCM.getInitialNotification should only be call on app bootstrap. like DidMount in our root component or outside of component lifecycle

bhosle-git commented 6 years ago

@evollu - we do have something to identify that its our app's notification.. the issue is that its a very old notif instance that had been processed earlier.. but let me try moving that outside the component lifecycle and see how it behaves..

@RuairiOliver - we recently moved to react-navigation from an earlier one that was deprecated.. not sure if its the same issue.. but yeah - I'll try getting the initial notification before anything else (from index.js) and update here..

thanks both..

dougmbarcellos commented 6 years ago

SO: Android 7.0 - Physical Device

I have the same problem. When opening the app for the first time through the notification, getInitialNotification() runs perfectly. After leaving the app idle for a while (I open other apps to force inactivity) and reopen it, getInitialNotification() is bringing exactly the same data as before. This is a problem.

I also did the test by opening the app after inactivity through another notification in the tray. The result was the same, instead of getInitialNotification () returning the last open notification data, it shows the notification data that opened the app.

Another similar situation is that if I open the app normally by the icon, I let it be inactive, so when I receive a notification and try to open it, getInitialNotification() returns only the data of the app initialization:

{
  "opened_from_tray":1,
  "fcm":{
    "action":"android.intent.action.MAIN"
  },
  "profile":0
}

When the app is in the background, but not sleeping / inactive, and I open the notification via the tray, everything works fine.

Is not there really a way to reset / delete the notification after getInitialNotification() is called?

I think it's the first time I write here. I would like to thank you for the excellent work, @evollu.

sfm2222 commented 6 years ago

I'm facing the same issue as @dowgsss .

Is not there really a way to reset / delete the notification after getInitialNotification() is called?

christianversloot commented 6 years ago

Facing the same issue. In addition, my app's notification listener does not show an alert when I tap the alert in the notification center.

evollu commented 6 years ago

@bhosle-git is your issue solved?

Is not there really a way to reset / delete the notification after getInitialNotification() is called? not as far as I know. It is reading from a native property, which doesn't cleared.

dougmbarcellos commented 6 years ago

In recent days I've been trying to solve this problem by researching, modifying, and debugging the native code. Even though my background has been based on Java, I find it difficult on Android. Unfortunately I did not find any solution.

Not unlike what @evollu has already said...

From what I saw, the firebase uses an Intent, which is "attached" to our MainActivity. In this case, the data we send is in the Intent extras. This data can be easily deleted or modified, but by the time Android kills the app and then the user opens it, we get back to the Intent data that was opened along with the app the first time. From what I've read, this data is in a "process" of Android, so whenever the app is restored, the data from that Intent comes back. It seems that some people who use firebase messaging with native java code also have the same problem.

"Solution" in my case...

For the time being, when handling the initial notification I will save the notification code within AsyncStorage and will only take some action on the notification if it is different from the last notification saved in AsyncStorage.

evollu commented 6 years ago

@dowgsss šŸ‘

dougmbarcellos commented 6 years ago

I have not given up yet. Yesterday, while I was in the barber shop waiting for my turn, I still insisted on how to solve the problem, cleanly. I did some research and at some point I came across an issue that I had seen several times in stackoverflow, but had not paid attention to the answer less voted:

https://stackoverflow.com/a/18307360/9070081

Code @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); /* * This overrides the original intent. */ setIntent(intent); }

I added this excerpt in my MainActivity and YES, the problem has been solved!

In short, there are now two situations that can happen considering that you opened the app and after some downtime the system killed the app:

At this second point, if you want to prevent the same action / notification from being run multiple times, you need to do an implementation using AsyncStorage or something, as I said in my last comment.

evollu commented 6 years ago

@dowgsss

are you saying that by calling setIntent it will override the response of getInitialNotification to be the newer intent?

But I have 2 questions

  1. Is there a way for iOS to do the same?
  2. This new intent will be broadcasted through notification callback to JS. so what is the benefit of changing the intent?
dougmbarcellos commented 6 years ago
  1. Is there a way for iOS to do the same?

Since I do not program for iOS I really do not know how to answer that. In fact, are there any reports of this same problem in iOS?

  1. This new intent will be broadcasted through notification callback to JS. so what is the benefit of changing the intent?

I'll always have the extra data updated in that specific situation where android kills the app and then I open the app via a notification. I will be able to see the data from this last notification.

evollu commented 6 years ago
  1. so far iOS shares the same behavior as Android, I'd prefer to keep them in sync to avoid surprises.
  2. if android kills the app and you open it through notification, getInitNotification should give your the new notification. @dowgsss
dougmbarcellos commented 6 years ago

@evollu I think there may be a misunderstanding about point 2. The problem is precisely because on Android, when the app is killed by the system (not by the user) when you reopen it through a notification, we are not receiving data from that last notification .

I think I can describe it through the following steps (without the change I suggested in MainActivity):

Expectation:

{
  opened_from_tray: 1,
  fcm: { action: 'android.intent.action.MAIN' },
  collapse_key: 'xxxxxxxxxxx',
  'google.message_id': 'yyyyyyyyyyyyyyyyyyyyyyy',
  from: 'xxxxxxxxxxxxxx',
  'google.ttl': 1111111,
  my_data_key: 'otherDataKey',
  'google.sent_time': 0000000000000
}

Reality(same data as the first notification):

{
  opened_from_tray: 1,
  fcm: { action: 'android.intent.action.MAIN' },
  collapse_key: 'xxxxxxxxxxx',
  'google.message_id': 'xxxxxxxxxxxxxxxxxxxx',
  from: 'xxxxxxxxxxxxxx',
  'google.ttl': 1111111,
  my_data_key: 'abc123',
  'google.sent_time': 0000000000000
}

Note:

When my app is only in backgroud and not dead, I can handle the notifications without any problem.

evollu commented 6 years ago

i will look into that

bhosle-git commented 6 years ago

sorry - had to be away for a couple of weeks. The issue is not resolved on my side either (I tried the change mentioned earlier - doing it outside the component lifecycle).

will try the change that dowgsss has mentioned as working for him.

evollu commented 6 years ago

@dowgsss A bit confused here.

  1. When app is running in background do you get notification callback when you tap on notification?
  2. When app is inactive (I don't know if android persist the state of app or not), do you get notification callback when you tap on notification?
dougmbarcellos commented 6 years ago

@evollu

  1. Yes, through the listener FCM.on(FCMEvent.Notification, fn).
  2. In this case, through the getInitialNotification().
evollu commented 6 years ago

case 2: You don't get any notification callback? Can I reproduce it in emulator? I follows steps here https://stackoverflow.com/questions/3417308/force-an-android-phone-to-sleep-in-order-to-test and wake up the device, tap the notification, still get JS callback.

dougmbarcellos commented 6 years ago

case 2: You don't get any notification callback?

No, I'm getting the callback data

evollu commented 6 years ago

@dowgsss then why not just act on the callback data?

dougmbarcellos commented 6 years ago

then why not just act on the callback data?

Because, following those steps I've explained, the data is not arriving correctly. It's coming up with the old notification data. Remembering that I only have problems in getInitialNotification().

I opened another app and turned off the screen, waited for couple minutes, come back and tap the notification. I will get a notification callback triggered

Through the getInitialNotification()?

evollu commented 6 years ago

getInitialNotification() should not be updated because the app is just suspended, not killed. The app status is persisted. Are you still on the same page when you resume the app?

dougmbarcellos commented 6 years ago

getInitialNotification() should not be updated because the app is just suspended, not killed. The app status is persisted. Are you still on the same page when you resume the app?

No, it's like the app starts again.

dougmbarcellos commented 6 years ago

I tested the emulator by following the suggested steps, but although the device was idle, the app was not killed by the system. So in this case yes, when I opened the notification / app I came across the same screen, the app was not loaded again.

dougmbarcellos commented 6 years ago

To see the problem the app must be killed by the system (not by the user).

dougmbarcellos commented 6 years ago

@evollu I tried again on the emulator forcing the app to be killed by the system. Follow these steps:

https://stackoverflow.com/a/34519656/9070081

But besides pressing the home button, you should start another app to kill the app process that has been minimized.

evollu commented 6 years ago

thanks, I can reproduce it now.

evollu commented 6 years ago

@dowgsss I've updated readme with the fix. thanks

evollu commented 6 years ago

@bhosle-git let me know if the solution works for you. it is in readme-> Android configuration -> last bullet point

bhosle-git commented 6 years ago

ok. the earlier change alone (that dowgsss pointed out from https://stackoverflow.com/a/18307360/9070081 didn't seem to have worked)..

will try your fix. thanks.

evollu commented 6 years ago

@bhosle-git try putting getInitNotification inside component lifecycle

karlmosenbacher commented 6 years ago

Before, I had

FCM.getInitialNotification().then(notif => {
  if(notif){
      console.log('Got initial notificaton: ' + JSON.stringify(notif));
  }
});

in the componentDidMount method, but that didnt triggered the initial notification at all. After put it outside the App class it worked.

evollu commented 6 years ago

@karlmosenbacher that's weird. this call should work any time.

karlmosenbacher commented 6 years ago

@evollu my thoughts exactly :+1: Gonna do some more investigation about this..

Johncy1997 commented 5 years ago

@karlmosenbacher i am getting notification is not defined error even i put outside class:( can you help me?