invertase / react-native-firebase

πŸ”₯ A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
https://rnfirebase.io
Other
11.71k stars 2.22k forks source link

onNotificationOpened not working on Android (background/foreground) #1272

Closed nopmengkoung closed 6 years ago

nopmengkoung commented 6 years ago

Issue

When my app is closed and I tapped on notification getInitialNotification is working fine on both platforms, but on android when I tapped on notification and my app is in background/foreground onNotificationOpened didn't triggered. When my app in foreground I display a local notification.

const notify = new firebase.notifications.Notification()
      .setNotificationId(notification._notificationId)
      .setTitle(notification._title)
      .setBody('Tap here to view more detail')
      .setData({...notification._data})
      .android.setChannelId('notif-channel')
      .android.setSmallIcon('ic_launcher')

    firebase.notifications().displayNotification(notify)

Environment

  1. Application Target Platform: Both
  1. Development Operating System: macOS High Sierra
  1. Build Tools:
  1. React Native version: 0.54
  1. React Native Firebase Version: 4.0.4
  1. Firebase Module: notifications
  1. Are you using typescript? no

Loving react-native-firebase? Please consider supporting their open collective:

πŸ‘‰ https://opencollective.com/react-native-firebase/donate

borapop commented 6 years ago

Same issue

Nicholas1490 commented 6 years ago

Hi,

I am having the same issue. The onNotificationOpened listener doesn't trigger when the app is in the background and I received the notification.

It triggers if the app is in the foreground. getInitialNotification also triggers when the app is dead.

yangnana11 commented 6 years ago

Hello,

It trigged for me though. But it doesn't get the notification data correctly, I've got undefined if it got when it goes background

       this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => {
            // Get the action triggered by the notification being opened
            const action = notificationOpen.action;
            // Get information about the notification that was opened
            const notification: Notification = notificationOpen.notification;
            alert(notification.body);
            firebase.notifications().removeDeliveredNotification(notification.notificationId);
        });
vomchik commented 6 years ago

the same problem :(

vomchik commented 6 years ago

my problem was in this .MainActivity class

Before:

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

After:

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

i forgot about this super.onNewIntent(intent);

Nicholas1490 commented 6 years ago

@vomchik didn't work for me :(

I was really hoping this was the solution. I remember using that snippet of code from another notification plugin and I took it out.

dengue8830 commented 6 years ago

in my case, i was missing the notification's data setup when building the notification on foreground notification event firebase.notifications().onNotification

new firebase.notifications.Notification()
      .setNotificationId(fcmNotification.data.notificacionId)
      .setTitle(fcmNotification.title)
      .setBody(fcmNotification.body)
      .setData(fcmNotification.data) // <- this little bastard

so, when tapping the notification data was undefined on firebase.notifications().onNotificationOpened even when the json that comes in firebase.notifications().onNotification had data field filled

nopmengkoung commented 6 years ago

On my side this issue is solved by doing nothing. When I tested on debug mode its not working but after I running release its working. That's weird for me too.

Salakar commented 6 years ago

Duplicate of https://github.com/invertase/react-native-firebase/issues/988 and others.

Please check there and the many other duplicates of this issue for a resolution, specifically see this comment https://github.com/invertase/react-native-firebase/issues/988#issuecomment-383175789 for a complete reference example.

Some common causes on Android are:


Loving react-native-firebase and the support we provide? Please consider supporting us with any of the below:

willdady commented 6 years ago

@Salakar This is not a duplicate of #988. That issue is referring to notifications not appearing in the foreground when triggered by the app itself. This issue is about the onNotificationOpened event not firing after tapping the notification.

I'm sending messages via the Cloud Messaging console and they appear fine in the simulator however when pressing the notification the onNotificationOpened event never fires. I've tried with and without explicitly creating a channel a as described here.

Also the getInitialNotification is always null when the app is cold-launched from pressing a notification.

gabrielbull commented 6 years ago

@salakar Please re-open, we are all experiencing this issue.

Salakar commented 6 years ago

@willdady sorry I actually meant this was a duplicate of https://github.com/invertase/react-native-firebase/issues/1230 - can I close this in favour of the other one?


Hey @gabrielbull been a while! Small world... πŸ˜„


@yangnana11 this is correct, see the below section from the docs: image Source: https://rnfirebase.io/docs/v4.3.x/notifications/receiving-notifications#4)-Listen-for-a-Notification-being-opened

If you need them then you can additionally send them as part of your data in your notification as well.

Salakar commented 6 years ago

Closing in favour of #1230 - definitely a duplicate this time πŸ™ˆ see my latest comment there as well.

Thanks

laukaichung commented 6 years ago
   @Override
   public void onNewIntent(Intent intent) {
       super.onNewIntent(intent);
       setIntent(intent);
   }

This solution doesn't work.

ZardozSpeaks commented 6 years ago

My solution to this problem is pretty implementation specific, but you never know what might help.

My issue was that I had a splash activity which was the actual launcher activity. To get the callbacks to fire in App.js I had to:

  1. Add "singleTop" to the activity tag for SplashActivity.java in AndroidManifest.xml
  2. Use "this.getIntent();" within the onCreate method of SplashActivity.java to intercept the intent from the firebase notification open event
  3. Use .getExtras() to take the bundle from the intercepted intent and attach it to a new intent forwarded to .MainActivity

As soon as .MainActivity had access to the intent all of the callbacks began firing on the correct events.

madvectr commented 6 years ago

I have gotten this to work after a lot of reading and some luck!

I haven't been able to get "onNotificationOpened" handler to react on notification receive. The only handler working responding is "onNotification" only when the app is in the foreground. To get the background notifications working I am using

await firebase.notifications().getInitialNotification();

and then processing as needed by the app.

This works in both cases when the app is closed or just running in background.

For those using any activity other than MainActivity as the launch activity, the notification opening will not be caught by the application (android) unless you pass the notification intent from the launch activity to MainActivity. Please follow @ZardozSpeaks post above for instructions on this.

https://github.com/invertase/react-native-firebase/issues/1272#issuecomment-417484397

@ZardozSpeaks Great catch!!

dakt commented 6 years ago

@msrivas Can you provide code please? I'm also stuck with same "onNotificationOpened" issue.

juanpaie commented 6 years ago

Solved the issue only on background using @ZardozSpeaks approach.

Under my SplashActivity.java, I added the following:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent fcmIntent = this.getIntent();
        Bundle bundle = fcmIntent.getExtras();

        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtras(fcmIntent);
        startActivity(intent);
        finish();
    }

I'm still trying to find the solution for foreground notifications.

awdhootlele commented 6 years ago

Solved the issue only on background using @ZardozSpeaks approach.

Under my SplashActivity.java, I added the following:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent fcmIntent = this.getIntent();
        Bundle bundle = fcmIntent.getExtras();

        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtras(fcmIntent);
        startActivity(intent);
        finish();
    }

I'm still trying to find the solution for foreground notifications.

I tried this and my onNotificationOpened() callback is firing now, but I get undefined as a body inside the notification. Also, as @ZardozSpeaks said, I also tried to pass the Bundle (using currentIntent.getExtras()) instead of the actual Intent, still getting undefined inside my notification.

In my main activity I have : @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); }

And in androidManifest.xml, I have set android:launchMode="singleTask" for both Main activity and Splash activity. Still no luck :(

ofri84 commented 6 years ago

in our app we use MainActivity which extends SplashActivity (from react-native-navigation) which extends AppCompatActivity. the rnfirebase implements ActivityEventListener. so:

  1. onNewIntent in MainActivity doesn't get called and even if it did, calling super.onNewIntent won't help us.
  2. since app is in the background onCreate in MainActivity/SplashActivity doesn't get called either.

I added: notification.android.setClickAction('...'); to the local notification so it created another intent which restart the app (after it came back to foreground) and then on getInitialNotification() get called with the local notification. I know its not a good solution but for now it helps us...

rizasifmap commented 5 years ago

Any updates on this? I am stuck here. Tried all solutions above.

daviswhitehead commented 5 years ago

I solved this with the following files

NotificationListeners.js

import firebase from 'react-native-firebase';
import { ts } from './FirebaseHelpers';
// https://rnfirebase.io/docs/v5.x.x/notifications/introduction

export const notificationDisplayedListener = () =>
  // app in foreground
  firebase.notifications().onNotificationDisplayed(notification => {
    console.log('onNotificationDisplayed');
    console.log(notification);
  });

export const notificationListener = () =>
  // app in foreground
  firebase.notifications().onNotification(notification => {
    console.log('notificationListener');
    console.log(notification);

    const localNotification = new firebase.notifications.Notification({
      sound: 'default',
      show_in_foreground: true,
      show_in_background: true,
    })
      .setNotificationId(notification.notificationId)
      .setTitle(notification.title)
      .setSubtitle(notification.subtitle)
      .setBody(notification.body)
      .setData(notification.data)
      .android.setChannelId('General')
      .android.setSmallIcon('@mipmap/ic_notification')
      .android.setColor('#F2C94C')
      .android.setPriority(firebase.notifications.Android.Priority.High);

    firebase.notifications().displayNotification(localNotification);
    console.log('displayed');
    firebase.notifications().removeDeliveredNotification(localNotification.notificationId);
  });

export const notificationOpenedListener = () =>
  // app in background
  firebase.notifications().onNotificationOpened(notificationOpen => {
    console.log('notificationOpenedListener');
    console.log(notificationOpen);
    const { action, notification } = notificationOpen;
    firebase.notifications().removeDeliveredNotification(notification.notificationId);
    console.log('OPEN:', notification);
  });

export const notificationTokenListener = userId =>
  // listens for changes to the user's notification token and updates database upon change
  firebase.messaging().onTokenRefresh(notificationToken => {
    console.log('notificationTokenListener');
    console.log(notificationToken);

    return firebase
      .firestore()
      .collection('users')
      .doc(userId)
      .update({ pushToken: notificationToken, updatedAt: ts })
      .then(ref => {
        console.log('savePushToken success');
      })
      .catch(e => {
        console.error(e);
      });
  });

SplashActivity.java

package com.daviswhitehead.shayr.android;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);

        // Pass along FCM messages/notifications etc.
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            intent.putExtras(extras);
        }

        startActivity(intent);
        finish();
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.daviswhitehead.shayr.android"
    xmlns:tools="http://schemas.android.com/tools" >

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

    <application
        android:name=".MainApplication"
        android:label="@string/APP_NAME"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:allowBackup="false"
        android:theme="@style/AppTheme"
        tools:replace="android:label">

        <activity
            android:name=".SplashActivity"
            android:theme="@style/SplashTheme"
            android:label="@string/APP_NAME"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".MainActivity"
            android:label="@string/APP_NAME"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
            android:windowSoftInputMode="adjustResize"
            android:exported="true"
            android:launchMode="singleTask" >
        </activity>

        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>

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

        <!-- NOTIFICATION DEFAULTS -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id"/>

        <!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
            See README(https://goo.gl/l4GJaQ) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_notification" />
            <!-- android:resource="@drawable/ic_notification" /> -->
        <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
            notification message. See README(https://goo.gl/6BKBk7) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/yellow" />

        <!-- SHARE ACTIVITY -->
        <activity
            android:noHistory="true"
            android:name=".share.ShareActivity"
            android:configChanges="orientation"
            android:label="@string/TITLE_ACTIVITY_SHARE"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.Share.Transparent" >
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                //  for sharing links include
                <data android:mimeType="text/plain" />
                //  for sharing photos include
                <data android:mimeType="image/*" />
            </intent-filter>
        </activity>

        <!-- FABRIC -->
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="c12e5c4bb8cd8ca855a8ada44fa3fde413006659" />

        <!-- REACT-NATIVE-FIREBASE NOTIFICATIONS -->
        <service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>

        <!-- SCHEDULED NOTIFICATIONS -->
        <receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"/>
        <receiver android:enabled="true" android:exported="true"  android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver">
            <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
            <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
jayzyaj commented 5 years ago

For those who were getting undefined on the data object when I console.log(notificationOpen.notification) on the returned promise of the onNotificationOpened it returns an object with a_data property instead of data.

Instead of this code block below:

 /*
    * If your app is in background, you can listen for when a notification is clicked / tapped / opened as follows:
    * */
    this.notificationOpenedListener = firebase.notifications().onNotificationOpened(notificationOpen => {
      const { data } = notificationOpen.notification;
      const { title, body } = data;
      console.log('Tapped the notifications when app is on background or foreground:', notificationOpen.notification);
      this.showAlert(title, body);
    });

I used this:

/*
    * If your app is in background, you can listen for when a notification is clicked / tapped / opened as follows:
    * */
    this.notificationOpenedListener = firebase.notifications().onNotificationOpened(notificationOpen => {
      const { _data } = notificationOpen.notification;
      const { title, body } = _data;
      console.log('Tapped the notifications when app is on background or foreground:', notificationOpen.notification);
      this.showAlert(title, body);
    });

Now everything works like a charm. I am using a newer firebase version btw

This is my package.json below: "react-native": "0.59.2", "react-native-firebase": "^5.2.3",

This is my project level build.gradle dependencies below:

    // Firebase dependencies
    implementation "com.google.android.gms:play-services-base:16.0.1"
    implementation "com.google.firebase:firebase-core:16.0.6"
    implementation "com.google.firebase:firebase-messaging:17.3.4"
LuongTruong commented 5 years ago

Hi guys, I am in the same situation, getInitialNotification and onNotificationOpened get call but both title and body are undefined

React native version: 0.57.0 react-native-firebase: 5.1.1 Running on AVD 8.1

I try everything above but no hope. Do you know any combination to make it work or I need to upgrade the version of react-native and react-native-firebase?

Thank you in advance!

mikehardy commented 5 years ago

I can't offer guidance on the specific issue but as regards upgrading I can think of a massive number of issues resolved between what you're running and current versions. You'll like the 'rn-diff-purge' project to take the fear out of react-native upgrades so you can get to 0.59.4 (actually 0.59.5 is releasing today I think), which will let you use react-native-firebase 5.3.1 and all the firebase SDK updates as well. Worth it I think

LuongTruong commented 5 years ago

thank you @mikehardy , I update the project to newest and it still undefined. However, I am able to receive the data from push notification. That is good for me

pierregoutheraud commented 5 years ago

I also ran into this problem (onNotificationOpened would not be triggered) and finally made it work. I followed https://github.com/invertase/react-native-firebase/issues/1272#issuecomment-421424104, you also need to change your launchMode from singleTop to singleTask (don't ask me why).

LuongTruong commented 5 years ago

Hi @pierregoutheraud , I set the launchMode to singleTask but the title and body still remain undefined. However, the data is able to be received. Thank you πŸ˜„

pierregoutheraud commented 5 years ago

@truongluong1314520 The documentation says: "On Android, unfortunately there is no way to access the title and body of an opened remote notification. You can use the data part of the remote notification to supply this information if it's required."

LuongTruong commented 5 years ago

Thank you @pierregoutheraud

danielzzz commented 5 years ago

in my case getInitialNotification was called but onNotificationOpened was not.

https://github.com/invertase/react-native-firebase/issues/1272#issuecomment-421424104 did not work for me (there was just a blank screen and the app would not start)

but I as getInitialNotification was called always whenever the app came to foreground I used this (combined with checking if I have already processed this notifictation) to workaround this problem.

I added getInitialNotification when initializing the App (to catch a cold start) and then boud it to appstate.change to call the callback when the app came back from background to foreground.

_handleAppStateChange = (nextAppState) => {
    console.log("APP STATE");
    console.log(this.state.appState);
    console.log(nextAppState);
    if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
      console.log('App has come to the foreground!')
      RNFirebase.notifications().getInitialNotification()
        .then(processNotification);
    }

    //update stored state
    this.setState({
      appState: nextAppState
    });
  }

componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange);
    console.log('hiding the splash');
    SplashScreen.hide();
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }
elizaMathaai commented 5 years ago

Have been struggling with background notitifcation no picking up in android... Got it to work finally. changed the launcher to singleTask. Thanks

r4mdat commented 5 years ago

Using react-native-bootsplash which already forwards the FCM Intent. Just had to set <activity android:name=".MainActivity" _android:launchMode="singleTask"_ ... /> and onNotificationOpened works as expected.

mikehardy commented 5 years ago

Interesting @r4mdat if I were to re-do my splash screen (which I may in the future) I would use react-native-bootsplash over react-native-splash-screen - it seems to be handling the Intent correctly https://github.com/zoontek/react-native-bootsplash/blob/master/android/src/main/java/com/zoontek/rnbootsplash/RNBootSplashActivity.java#L27 which is why it doesn't have the problems splash-screen had when chaining Activities

muhammad-ihsan commented 4 years ago

I came here looking for the solution of why firebase.notifications().onNotificationOpened not triggered on background, and not using any additional package like react-native-bootsplash or react-native-splash-screen. I got stuck a month for this issue :(

Dylan0916 commented 4 years ago

onNotificationOpened can be triggered, but _title and _body are undefined. πŸ˜•

"react-native": "0.60.6" "react-native-firebase": "5.5.6"

roger-ngx commented 4 years ago

android document said "The other modes β€” singleTask and singleInstance β€” are not appropriate for most applications, since they result in an interaction model that is likely to be unfamiliar to users and is very different from most other applications." - I wonder what is "unfamiliar" behavior ?

mikehardy commented 4 years ago

React-native programming model for Android is that there is only one activity and really it should always be on top and all by itself. That makes sense since really it's javascript showing "screens" inside the activity.

In normal Android apps each screen is an Activity. And you might have the same screen showing different pieces of data, so two Activities on the stack with other Activities on top etc - so the normal Android app has a different Activity stack model and singleTask wouldn't fit it.

jbdevelop commented 4 years ago

Solved the issue only on background using @ZardozSpeaks approach.

Under my SplashActivity.java, I added the following:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent fcmIntent = this.getIntent();
        Bundle bundle = fcmIntent.getExtras();

        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtras(fcmIntent);
        startActivity(intent);
        finish();
    }

I'm still trying to find the solution for foreground notifications.

Amazing! It works for me. Thank you! I also changed launchMode activity .MainActivity from singleTop to singleTask.

mikehardy commented 4 years ago

react-native-boot-splash is the thing to use. It passes Intent data correctly and is well maintained

thaitd96 commented 3 years ago

@daviswhitehead thank you, it worked for me!!!

TwistedMinda commented 1 year ago

Issue seem to be persisting and not related to react-native-splash-screen : https://github.com/wix/react-native-notifications/issues/958

autimio commented 4 months ago

Using react-native-notifications worked for me.

import { Notifications } from 'react-native-notifications';
Notifications.getInitialNotification().then(async remoteMessage => {}).catch(err => { console.error(err, 'err') })