React-native-firebase: cannot receive notification foreground android

Created on 10 Jun 2018  路  16Comments  路  Source: invertase/react-native-firebase

Hi I am using the latest rnfirebase.My problem is that when I send message to firebase console my app cannot receive if it is in foreground but when it is background it can received.
this is my simple code taken from the docs.

componentDidMount() {

        firebase.messaging().requestPermission()
            .then(() => {
                // User has authorised
                console.log("user authenticate");
                this.notificationDisplayedListener = firebase.notifications().onNotificationDisplayed((notification: Notification) => {
                    // Process your notification as required
                    // ANDROID: Remote notifications do not contain the channel ID. You will have to specify this manually if you'd like to re-display the notification.
                    console.log("then notification",notification);
                    firebase.notifications().displayNotification(notification);
                });
                this.notificationListener = firebase.notifications().onNotification((notification: Notification) => {
                    // Process your notification as required
                    console.log("then notificationListener",notification);
                    firebase.notifications().displayNotification(notification);
                });

            })
            .catch(error => {
                // User has rejected permissions
                console.log("user rejected");
            });
        this.makeRemoteRequest();
    }
    componentWillUnmount() {
        this.notificationDisplayedListener();
        this.notificationListener();
    }

Thank you in advance.

Most helpful comment

had the same problem background and closed app notification was listened and worked fine but for foreground notification its not working this doc helped me
https://rnfirebase.io/docs/v4.2.x/messaging/android#Update-Android-Manifest

All 16 comments

I am experiencing the same issue

had the same problem background and closed app notification was listened and worked fine but for foreground notification its not working this doc helped me
https://rnfirebase.io/docs/v4.2.x/messaging/android#Update-Android-Manifest

same problem.

Without a version of RNFirebase, React Native or even the platform this problem is happening on, it's incredibly difficult to help you.

Please complete the issue template and re-open.

@ezekel , the onNotificationDisplayed is executed when the notification is displayed. Your handler for this event is calling displayNotification... I think this causes infinite recursion.

@chrisbianca ,
here is my package.json, I'm in android platform.

 "react-native-firebase": "^4.2.0",
 "react-native": "0.55.3",

@aMarCruz , here is my full code,

 componentDidMount() {


        firebase.messaging().requestPermission()
            .then(() => {
                // User has authorised
                console.log("user authenticate");
                firebase.messaging().getToken()
                    .then(fcmToken => {
                        if (fcmToken) {
                           console.log("fcm token",fcmToken);
                        } else {
                           console.log("No tokent");
                        }
                    });

                this.messageListener = firebase.messaging().onMessage((message) => {
                    // Process your message as required
                    console.log("message",message);
                    firebase.notifications().displayNotification(message);
                });


                const channel = new firebase.notifications.Android.Channel('channelId', 'Test Channel', firebase.notifications.Android.Importance.Max)
                    .setDescription('My apps test channel');
                firebase.notifications().android.createChannel(channel);


                this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => {

                    const action = notificationOpen.action;

                    const notification: Notification = notificationOpen.notification;
                });

                this.notificationDisplayedListener = firebase.notifications().onNotificationDisplayed((notification: Notification) => {



                    firebase.notifications().displayNotification(notification);
                });
                this.notificationListener = firebase.notifications().onNotification((notification: Notification) => {


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

                    firebase.notifications()
                        .displayNotification(localNotification)
                        .catch(err => console.error(err));




                });

            })
            .catch(error => {
                // User has rejected permissions
                console.log("user rejected");
            });
        this.makeRemoteRequest();
    }
    componentWillUnmount() {
        this.notificationDisplayedListener();
        this.notificationListener();
        this.messageListener();
        this.notificationOpenedListener();

    }

Thank you in advance.

please re open this I already provide what you need..I'm still stuck with this problem

@ezekel , It seems that you are receiving data-only messages and from these messages creating local notifications. Is it? (I do it that way)... then you need only two handlers: onMessage and onNotificationOpened.

These are code fragments of my App (_I can't publish more, this is closed-source_):

This is the function (Headless JS) that receives the messages when the App is closed:

// From src/services/bgMessaging.ts
import { Firebase } from 'react-native-firebase' // typings
import Log from 'react-native-android-log'
import { sendNotification } from './notificationHelpers'

export default function bgMessaging (message: Firebase.messaging.RemoteMessage) {
  Log.v('[bgMessaging] Recibe mensaje.')
  return sendNotification(message)
}

This is the regular code, for when the App is not closed:

// From src/services/notificationServices.ts
import firebase, { Firebase } from 'react-native-firebase'
import { getChannelId, getUnreadCount, sendNotification, UNREAD_KEY } from './notificationHelpers'
import { tryToOpenFromApp } from './navigationService'
import Log from 'react-native-android-log'
import Settings from 'react-native-cross-settings'
// . . . deleted code

const IS_OREO = Platform.Version >= 26

export const notificationService = (function () {
  // . . . deleted code

  /**
   * A data message is received with the App at front.
   * The same action is executed as when the App is in the background or closed.
   */
  const onMessage = (message: Firebase.messaging.RemoteMessage) => {
    console.log('onMessage:', message)
    sendNotification(message)
  }

  /**
   * This function tries to open the notification the App immediately, if it doesn't get it,
   * it registers it in the state to open it asap.
   */
  const onNotificationOpened = (openned: Firebase.notifications.NotificationOpen, init?: boolean) => {
    const { notification } = openned
    const data = notification.data as MessageData
    console.log('[NOTS] onNotificationOpened:', notification)

      // Skip if it comes from getInitialNotification, else check with the router
      if (init !== true && tryToOpenFromApp(data)) {
        return  // ok, redirecci贸n inmediata
      }

      const dispatch = getStore().dispatch  // using Redux
      if (dispatch) {
        dispatch(msgsActions.registerNotification(data))
      }
  }

  // . . . deleted code

  const start () => {
    // Monitoriza el estado de la conexi贸n
    if (!data.connHandlerSet) {
      data.connHandlerSet = true
      NetInfo.getConnectionInfo().then(onConnection)
      NetInfo.addEventListener('connectionChange', onConnection)
    }
    if (data.started) {
      console.log('[NOTS] notificationService iniciado.')
      return
    }
    data.started = true
    AppState.addEventListener('change', onAppState)

    console.log('[NOTS] Iniciando servicio...')
    firebase.messaging().hasPermission().then((granted) => {
      if (granted) {
        const notifications = firebase.notifications()
        const messaging = firebase.messaging()

        createChannels()

        data.listeners.push(
          messaging.onTokenRefresh(refreshToken),
          // ======= @ezekel : THIS IS FOR RECEIVING MESSAGES =======
          messaging.onMessage(onMessage),
          // ======== @ezekel : TO OPEN THE CARD IN THE APP =========
          notifications.onNotificationOpened(onNotificationOpened)
        )

        // . . . more code deleted

        notifications.getInitialNotification().then((data) => {
          if (data) {
            console.log('[NOTS] getInitialNotification:', data.notification)
            // ====== @ezekel : CALL THE SAME HANDLER AS MANUAL OPEN =======
            onNotificationOpened(data, true)
          }
        }).catch(console.warn)

        console.log('[NOTS] Servicio iniciado.')
      } else {
        console.log('[NOTS] Notificaciones deshabilitadas.')
      }
    })
  }

  // . . . deleted code
  return {
    start,
    subscribeToTopics,
  }
})()

This is a fragment with the sendNotification function in notificationHelpers:

// From src/services/notificationHelpers.ts
// . . . precedent code deleted

/**
 * Env铆a la notificaci贸n intentando no generar error
 */
const sendIt = (notification: Firebase.notifications.Notification) => {
  return firebase.messaging().hasPermission().then((yes) => {
    if (yes) {
      try {
        return firebase.notifications().displayNotification(notification)
          .catch((err) => {
            Log.e(`[sendNotification] ERROR: ${err}`)
            return Promise.resolve()
          })
      } catch (err) {
        Log.e('[sendNotification] Error displaying notification: ' + err)
      }
    }
    return Promise.resolve()
  })
}

/**
 * Crea y muestra una notificaci贸n a partir de un mensaje recibido desde CFM.
 *
 * __NOTE:__ Esta rutina puede llamarse con la App abierta, cerrada o en el fondo.
 *
 * @param message Mensage del servidor
 * @param noCount Si `true`, no regitrar la alerta en la lista de no le铆das
 */
export function sendNotification (message: Firebase.messaging.RemoteMessage) {
  Log.v('[sendNotification] #1')
  const payload: MessagePayload = message.data as any || {}
  const medical = payload.category === MEDICAL_CATEGORY_ID
  const cmtyInfo = getCmtyInfo(payload.cmty)
  if (!cmtyInfo) {
    Log.v('[sendNotification] Comunidad no suscrita.')
    return Promise.resolve()
  }

  // . . . deleted code

  const notification = new firebase.notifications.Notification()
    .setNotificationId(message.messageId)
    .setTitle(payload.title || alertCategory.getTitle(payload.category) || '?')
    .setSubtitle(_T('notification.By') + payload.senderName)
    .setData({
      id: payload.id,
      type: payload.type,
      sender: payload.sender,
      senderName: payload.senderName,
      cmtyInfo,
    } as MessageData)

  // Si se env铆a body con cadena vac铆a, se crea una l铆nea en blanco
  if (payload.body) {
    notification.setBody(payload.body)
  }
  if (medical || isPlaySoundActive()) {
    notification.setSound('default')
    Log.v('[sendNotification] setSound')
  }

  if (Platform.OS === 'android') {
    //notification.android.setLargeIcon(alertCategory.getIcon(data.category))
    notification
      .android.setAutoCancel(true)
      .android.setCategory(firebase.notifications.Android.Category.Message)
      .android.setChannelId(getChannelId(payload.type))
      .android.setColor(medical ? variables.medicalColor : variables.scheme.primaryColor)
      .android.setSmallIcon(STATUS_ICON)
      .android.setWhen(message.sentTime || Date.now())
      .android.setShowWhen(true)
    if (payload.place) {
      notification.android.setBigText(payload.place)
    }
    if (medical) {
      notification
        .android.setLargeIcon('ca_medic')
        .android.setCategory(firebase.notifications.Android.Category.Alarm)
        .android.setColorized(true)
    } else {
      notification.android.setCategory(firebase.notifications.Android.Category.Message)
      // Los grupos se soportan a partir de SDK 24
      if (Platform.Version >= 24) {
        notification.android.setGroup(ALERTS_GROUP)
        sendSummary(notification.data)
      }
    }
    // Campos para versiones anteriores a los canales de Oreo
    if (!IS_OREO) {
      if (medical) {
        notification
          .android.setPriority(firebase.notifications.Android.Priority.Max)
        ;(notification.android as any)._visibility = firebase.notifications.Android.Visibility.Public
        //.android.setVisibility(firebase.notifications.Android.Visibility.Public)
      } else if (payload.type === MessageDataEnum.Alert) {
        notification
          .android.setPriority(firebase.notifications.Android.Priority.High)
      }
    }
  }

  // Registra la alerta como no le铆da, excepto si se pide no registarla
  if (payload.type === MessageDataEnum.Alert) {
    registerUnreadAlert(payload.id)
  }

  Log.v('[sendNotification] display notification.')
  return sendIt(notification)
}

Then, in the main component in App.tsx the service is started:

// From src/App.tsx
// . . .
import { notificationService } from './services'
// . . .
class App extends React.PureComponent<Props> {

  private _store: AppStore

  constructor (props: Props) {
    super(props)
    Log.d('[App] EN EL Ctor')

    this._store = getStore()

    // El servicio de nitificaciones debe cargarse cuanto antes
    // pero no fuera de los componentes de la UI.
    notificationService.start()  // <======== START MONITORING
  }
// . . . more

Last, index.js:

require('ReactFeatureFlags').warnAboutDeprecatedLifecycles = false
import { AppRegistry } from 'react-native'
import App from './src/App'
import bgMessaging from './src/services/bgMessaging'

AppRegistry.registerComponent('app_name', () => App)
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => bgMessaging)

Please study the structure, it works like a charm in my App (currentry in Beta).
Hope this help you and sorry my bad english.

@aMarCruz can I ask why you say "data-only messages" ? can you please enlighten my mind

@ezekel ,

The React Native Firebase Messaging Module deals exclusively with data-only messages.

For notification-only and notification + data FCM messages please see the Notifications module.

See https://rnfirebase.io/docs/master/messaging/introduction

On the server side (with the admin SDK) the difference is in the properties you use.

This sends a data-only message to clients subscribed to a specific topic (alrt.community in this case):

    // . . .
    const message: TopicMessage = {
      topic: alrt.community,
      data: {
        id,
        type: cmnt.type,
        category: alrt.category,
        sender: cmnt.sender,
        senderName: cmnt.senderName,
        body: isLoc ? undefined : cmnt.body,
        place: isLoc ? cmnt.body : (eventPlace && eventPlace.place),
      },
    }
    return admin.messaging().send(message)
      .catch((err) => {
      // . . .

For notification or notifications+data messages you must use the notification property in the object passed to admin.messaging().send.

See https://firebase.google.com/docs/reference/admin/node/admin.messaging.Messaging#send

@aMarCruz , Thank you for the quick reply, can I ask last question.

this part here is this sending notification to other devices ?

if (Platform.OS === 'android') {
    //notification.android.setLargeIcon(alertCategory.getIcon(data.category))
    notification
      .android.setAutoCancel(true)
      .android.setCategory(firebase.notifications.Android.Category.Message)
      .android.setChannelId(getChannelId(payload.type))
      .android.setColor(medical ? variables.medicalColor : variables.scheme.primaryColor)
      .android.setSmallIcon(STATUS_ICON)
      .android.setWhen(message.sentTime || Date.now())
      .android.setShowWhen(true)
    if (payload.place) {
      notification.android.setBigText(payload.place)
    }
    if (medical) {
      notification
        .android.setLargeIcon('ca_medic')
        .android.setCategory(firebase.notifications.Android.Category.Alarm)
        .android.setColorized(true)
    } else {
      notification.android.setCategory(firebase.notifications.Android.Category.Message)
      // Los grupos se soportan a partir de SDK 24
      if (Platform.Version >= 24) {
        notification.android.setGroup(ALERTS_GROUP)
        sendSummary(notification.data)
      }
    }

Thank you in advance

@ezekel , these code is sending displaying a local notification (only to the current device).

In my examples, I'm sending data-only messages to different topics, to which users are suscribed. Then, on each user device, I create a local notification that is what the user sees.

Why this? because the API of the admin SDK is very limited and because the message that travels through the network is lighter. In the "front" I can customize the notification to my liking, translate text, use user-specific preferences of the App, etc.

@aMarCruz , Thank you so much. it work's now

send only data key.

let payload = {
data: {
title: 'title',
body: 'body',
}
}

Was this page helpful?
0 / 5 - 0 ratings