Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

background app - on("notification") not triggered after notification click #164

Closed
atlanteh opened this issue Oct 15, 2016 · 19 comments
Closed

Comments

@atlanteh
Copy link

Versions:
rn - 0.34.1
fcm - 2.3.2

I have an android app. When I click on home button to move the app to background and then sending a notification, the notification goes to notification area, but when I click on the notification, the app goes to foreground directly (it's not re-launching) and the notification data is not passed to the app.
Is this related to the hybrid notification problems? I thought that the hybrid problem is just when not clicking on the notification, but when clicking it should pass the data to the app somehow.

notification payload:

{
        priority: 'normal',
        contentAvailable: true, //for ios
        delayWhileIdle: true,
        timeToLive: fcmConfig.timeToLive,
        restrictedPackageName: 'my app id',
        dryRun: fcmConfig.isDryRun,
        data: {
            myData: {
                id: '123456',
            }
        },
        notification: {
            title: 'Hello world title',
            icon: "ic_launcher",
            body: 'Hello world body',
            sound: 'default',
        },
    }

javascript:

///When app started:
FCM.getInitialNotification()
        .then(notification => {
            if (notification && notification.myData) {
                alert(notification.myData);
            }
        });
FCM.on('notification', (notif) => {
        alert("on: " + notif.myData);
});
@dslounge
Copy link

I have this same issue, and it's driving me nuts. This project's documentation isn't helpful. It just says, "it's tricky!" and links to a really old GCM issue: google/gcm#63

Looks like if you want a hybrid notification to work properly when the app is in the background, you need to pass a click_action in your notification payload. Then in AndroidManifest.xml set MainActivity to respond to an intent with that click_action.

Feels like this behavior should be better documented. It's taken a lot of trial and error to understand what's really going on.

@atlanteh
Copy link
Author

So u figure it out? I tried using click_action but still couldn't get it to work..

@dslounge
Copy link

Make sure you did this part correctly: https://github.com/evollu/react-native-fcm#config-for-notification-and-click_action-in-android. That's something that tripped me up for a bit.

@atlanteh
Copy link
Author

Are you sure we're talking about the same scenario?
In my scenario, the app is in the background, still live and kicking..When I click the notification, the app doesn't load from scratch, it just reappears, just like pressing the home button and then pressing the app again..
I'm not talking about when the app is in the background for few mins which then it gets killed or whatever..
I did everything as u said but nothing works..

{
        priority: 'normal',
        contentAvailable: true, //for ios
        delayWhileIdle: true,
        timeToLive: fcmConfig.timeToLive,
        restrictedPackageName: 'my app id',
        dryRun: fcmConfig.isDryRun,
        data: {
            myData: {
                id: '123456',
            }
        },
        notification: {
            title: 'Hello world title',
            icon: "ic_launcher",
            body: 'Hello world body',
            sound: 'default',
            click_action: 'myAction',
        },
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myPackage"
    android:versionCode="5"
    android:versionName="0.1.5">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <permission
        android:name="${applicationId}.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:theme="@style/AppTheme"
      android:name=".MainApplication">

      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:screenOrientation="nosensor"
        android:windowSoftInputMode="adjustResize" 
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter>
          <action android:name="myAction" />
          <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

      </activity>

      <service android:name="com.evollu.react.fcm.MessagingService">
        <intent-filter>
          <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
      </service>

      <service android:name="com.evollu.react.fcm.InstanceIdService" android:exported="false">
        <intent-filter>
          <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
      </service>

      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

Even tried MainActivity.java:

    @Override
    public void onNewIntent (Intent intent) {
      super.onNewIntent(intent);
        setIntent(intent);
    }    

Nothing seems to get the notification data to the app.
Just to be clear..when the app is closed, and I get the notification, the data is passed to the app through FCM.getInitialNotification.
After checking a little bit I can identify two problems:

  • App running in background and a notification appears. clicking notification brings app to foreground with no data..
  • App closed. Two notifications appear. clicking the first one, the notification gets to the app. Then, when app in foreground (or background), clicking the second one brings app to foreground with no data.

@atlanteh
Copy link
Author

Apparently when the app is in the background or even in foreground, when clicking a notification, then:
FCM.getInitialNotification() is populated with the correct notification.
So the following code does seem to work (at least on android):

    handleChange(change) {
        if (change !== 'active') {
            return;
        }
       // Closing screen and opening again does run this again and will get the same notification..so you might want to add code to check if you already got this notification..
        FCM.getInitialNotification().then(notification => {
           if (notification.myData) {
                   alert(`init: ${notification.myData}`);
            }
        });
    }
    componentWillMount() {
        AppState.addEventListener('change', this.handleChange);
    }

    componentWillUnmount() {
        AppState.removeEventListener('change', this.handleChange);
    }

Is this the way to go?

@sibelius
Copy link

U just need to call getInitialNotification on componentDidMount, no need to call it every time the appstate changes

@dslounge
Copy link

dslounge commented Oct 18, 2016

I didn't need to add an AppState listener whatsoever. To summarize, this is how I'm handling notifications in my app, there's 3 scenarios:

App isn't Running:

  • Firebase SDK will display a system notification. Pressing the banner will open the app, and getInitialNotification() will fire. This is a promise that seems to always fire (with an empty notification if there isn't an initial notification), so you can show a loading screen and wait until this promise resolves to show a screen based on the notification

App is in Foreground:

  • Firebase SDK wont fire a system notification. Instead, the data payload will get passed through FCM.on('notification' event. If you want to show a system notification, here you need to trigger a manual, local notification. Be careful with this, since the local notification will fire FCM.on('notification' itself, and you could have a loop creating infinite notifications.

App is in Background:

  • Firebase SDK will display a system notification. Pressing the banner will open the app with an intent, specified by the click_action. The activity needs to be specified as singleTop and be able to handle that intent. The Activity will show and because it's already running, FCM.on('notification' event will fire.

Hopefully that's helpful. That's been my experience with this package, and I'm running Android Marshmallow. It might be different on other phones.

To be honest with you, I think the right thing todo is to write my own Firebase listening service, use just data notifications, and fire local notifications when those are received. That's what I'm going to do eventually. Getting all this to work was a big pain, and it's mostly because of Firebase.

More notes....

  • I didn't change MainActivity.java
  • using "react-native": "0.33.0", "react-native-fcm": "2.3.0",

Sample payload:

{
  "to" : "token-goes-here",
  "notification" : {
    "title" : "Story title",
    "body" : "location name",
    "icon" : "ic_stat_notify",
    "sound": "default",
    "click_action": "geosocial.story"
  },
  "data" : {
    "title" : "Story title",
    "body" : "location name",
    "icon" : "ic_stat_notify",
    "story_id" : "10279"
  },
}

Relevant parts of AndroidManifest (notice geosocial.story intent)

<application
      android:name=".MainApplication"
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher_geosocial"
      android:theme="@style/AppTheme">

      <!-- For displaying local notifications -->
      <receiver android:name="com.evollu.react.fcm.FIRLocalMessagingPublisher"/>

      <!-- For listening to firebase messages -->
      <service android:name="com.evollu.react.fcm.MessagingService">
        <intent-filter>
          <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
      </service>

      <!-- For handling rotating firebase ids -->
      <service android:name="com.evollu.react.fcm.InstanceIdService" android:exported="false">
        <intent-filter>
          <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
      </service>

      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
          <action android:name="geosocial.story" />
          <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
      <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/google_maps_api_key"/>
    </application>

@kylebebak
Copy link

I've been struggling with this all day. The FCM API seems to have some issues...

Regarding the docs for react-native-fcm, it says that if the app is running in the background, the following applies:

Android will receive notificaton from FCMNotificationReceived event

  • if you pass notification payload, it will receive data when user click on notification
  • if you pass data payload only, it will receive data when in background

This, however, is not true. The FCM.on('notification' callback isn't called if I pass both notification and data payloads. It's only called if I pass data only.

Given this constraint, how do I create a hybrid notification, i.e. one that both invokes a callback in the application and displays a system notification?

Using "react-native": "^0.34.0", "react-native-fcm": "^2.2.2",

@kylebebak
Copy link

@dslounge

Ok, I think I've got it now. Thanks for explaining this thoroughly.

Still, I'm totally mystified as to why data is handled in OnMessageReceived when it's passed on its own, but if it's passed with notification it gets handled in the extras of the intent.

This really goes against the principle of least astonishment, and sort of screws up what would otherwise be an intuitive API.

screen shot 2016-10-25 at 7 43 17 pm

@dslounge
Copy link

@kylebebak I'm glad you figured it out. It was really confusing for me as well, and I had to do a lot of trial and error. FCM is confusing, and this package's documentation is confusing as well. I'm also using this for iOS and it works on iOS 10 but it doesn't work on iOS 9 for some reason.

I think the main error is wanting the firebase SDK to display the notification for you. It's really tempting to use the notification field on the payload. But the way they handle it is weird and doesn't have all the features you'd want. For my use case, I just want to display a banner in all cases, I don't care if the app is in the foreground, background, killed. Firebase doesn't do that. :/

@dg92
Copy link

dg92 commented Oct 31, 2016

@kylebebak @dslounge please help me out with App is in Background state not in killed state..i have generated a presentLocalNotification in FCM.on('notification') event so when i receive notification when app is in background state, and when i click on notification FCM.on('notification') gets fired and i have 1 more notification triggered. how do i stop one more triggering.. pls help.

@atlanteh
Copy link
Author

atlanteh commented Nov 3, 2016

I don't think u can..You do however have two useful properties on the notification:
local_notification - tells u if the notification is local or remote.
opened_from_tray - if the notification is triggered because it was opened from tray or because u triggered it (locally or remotely)
Use these in the handler to ignore the events u don't need

@sibelius
Copy link

sibelius commented Dec 12, 2016

@atlanteh can we close this?

@atlanteh
Copy link
Author

Yes.

@tushar2812
Copy link

i got a solution for that.
just put below code in oncreate method of launcher activity.

if (bundle != null) {
        String value = bundle.getString("key");
        if (value != null) {

            startActivity(new Intent(MainActivity.this, secActivity.class));
        }
}

when app is in background or killed,FCM will not call onmessagerecieved method,but it will send data to system tray to display notification.so datapayload(sent from fcm console) will not be handled by onmessagerecieved method.when user click on notification,it will launch default activity of app and datapayload will be passed by intent .so making change in oncreate method of launcher activity(as above)we can get datapayload even when app is in background or killed.(ex key is sent by fcm console).when app is in foreground datapayload and will be handled by onmessagerecieved method of fcm service.

@foggy1
Copy link

foggy1 commented May 16, 2017

@atlanteh @dslounge @kylebebak Do any of you still use this library? I'm completely mystified. Despite specifying click_action and having the matching intent, no combination of notification and data currently fires off the main callback at all on android, and I have no idea how to even go about debugging it. My app is receiving notifications in the background, but opening it from tray never, ever gets recognized.

@jayneshshah
Copy link

@dslounge, Followed steps given by you but having same issue. Can you please help to figure out this issue?

@christianversloot
Copy link

Did anyone of you manage to fix it @jayneshshah @foggy1 ?

@nkov
Copy link

nkov commented Mar 3, 2018

@foggy1 Same here. It works in one app, but not the other, and can't figure out why. The intent is registered and the background notification displays but clicking on it doesn't fire an event in Android. Works fine on iOS.

The strange thing is, if chrome developer console is open, then it works perfectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants