Giter Site home page Giter Site logo

Comments (37)

luisfuertes avatar luisfuertes commented on July 20, 2024 7

With pressAction in displayNotification.android data app is opened. (Solution in this issue invertase/react-native-notifee#31)

notifee.displayNotification({
        ...message,
        ...notification,
        android: {
          channelId: this.channelId,
          pressAction: {
            launchActivity: 'default',
            id: 'default'
          }
          //smallIcon: 'ic_notification'
        }
      })

Now all works fine, only need a notifee event to local notifications tapped on app background.

Event like messaging().onNotificationOpenedApp(remoteMessage => {}) but with Notifee

from notifee.

roni-castro avatar roni-castro commented on July 20, 2024 4

@Ehesp If possible, it would be nice to have an example of the full integration between react-native-firebase/messaging and react-native-notifee, because it is too difficult implement an app that works fot ALL use cases below using both these libs. We never know if one of this libs have some bugs or our app have some native problem, so I suggest the owners to create a full example that works to all use cases.

The testing cases must be:

  • Receive push notification on Foreground (app is visible to the user)

  • Receive push notification on Background (the device is locked, the application is running & is in not in view (minimized), the application is killed/quit.)

  • To ALL the cases above the app must activate a callback (when the view is rendered) so we can redirect the user to a specific screen.

I have got almost all cases using both the libs, but on the specific case of the application is killed/quit both the onBackgroundEvent and notifee.getInitialNotification are called and I can't use the onNotificationOpenedApp as it is never called on Android.

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024 2

Any update?

from notifee.

Ehesp avatar Ehesp commented on July 20, 2024 2

We do have a repo internally which does this - we'll need to rework it a bit as it's got some private stuff in there but no reason we can't make it open.

from notifee.

netbull avatar netbull commented on July 20, 2024 1

@mikehardy Yes, in the production build it works...

/**
 * @format
 */
import React from 'react';
import {AppRegistry} from 'react-native';
import messaging from '@react-native-firebase/messaging';

import notificationService from 'services/notificationService';
import {name as appName} from './app.json';
import App from './App';

messaging().setBackgroundMessageHandler(async remoteMessage => {
  await notificationService.onMessageReceived(remoteMessage);
});

function HeadlessCheck({isHeadless}) {
  if (isHeadless) {
    // App has been launched in the background by iOS, ignore
    return null;
  }

  return <App />;
}

AppRegistry.registerComponent(appName, () => HeadlessCheck);

I think this code is executed as earlier as possible..
However, I continue to use Notifee to display the messages as the issue with Data only messages is solved.

Thank you for your help!

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024 1

And how about method like messaging().onNotificationOpenedApp(remoteMessage => {}) but with Notifee?

from notifee.

netbull avatar netbull commented on July 20, 2024 1

notifee.getInitialNotification() works for me when the app is killed and after tapping the notification displayed by notifee.displayNotification()

from notifee.

mahpat16 avatar mahpat16 commented on July 20, 2024 1

Any update on messaging().onNotificationOpenedApp(remoteMessage => {}) being added to Notifee. From my testing.

notifee.getInitialNotification() - is called when the app is not running at all.
notifee.onForegroundEvent() - is called when the app is in foreground.

When the app is running and minimized. We get the
notifee.onBackgroupEvent() - But this event does not run in the react native context. What we want is a callback that is in the recat native context so we can show a specific screen to the user. Without a callback how do we find out when the app comes back in the foreground?

from notifee.

meliodev avatar meliodev commented on July 20, 2024 1

Now to explain clearly my issue. onBackgroundEvent is mounted before my first app render (as suggested by notifee documentation).

I think you mean registered? React components are "mounted" in a view hierarchy, but handlers / callbacks etc are just registered. But! I understand what you mean. And sure. It's possible on Android to have onBackgroundEvent fire while no App is registered because of headless mode. On iOS it's not really possible as the whole App loads, there is no background.

That's why I could not get a reference to my navigator.
Is there no issue to initialize onBackgroundEvent after rendering my app ?

There is not, you will need some sort of storage state like redux or ReSub where onBackgroundEvent can store that it received something, and during app component mount you should check on your welcome screen whether anything was received that it needs to forward for

The same is true of dynamic links received in the background, notifications opening the app etc. Register handlers, have those handlers take note that they were called and store that in state, have your welcome screen check state and forward as necessary. That's the pattern I use anyway, works well for me?

Thank you @mikehardy now I start to understand better how things work. I will try to follow your tips !
Cheers

from notifee.

billnbell avatar billnbell commented on July 20, 2024 1

Since I purchased Notifee this is still a major issue. We did find a work around, but i was not good, until you see the comment at the end of the message. I am sure this can help others.

  1. When a background message is sent we enter notifee.onBackgroundEvent() which is great. But we are in index.js and not in App.tsx. So we have no way to direct the "click" from the displayed notification to the right page.
  2. We decided to use AsyncStorage() to set something in the index.js, and have App.tsx read it and do a redirect. This works - and based on the AsyncStorage() setting we know what page to go to.

We would like Notifee to fix this issue and it is the same on Android and IOS. We cannot get onForegroundEvent to ever fire on a background notification. We see EVENT type 3, and then 1 fire inside notifee.onBackgroundEvent() when they click, and the onForegroundEvent never sees the message.

Here is the answer.

For your home page - if using React Navigation. Add this not in App.tsx, but add it into your actual page that renders when your site comes up. That was the key for us. notifee.getInitialNotification() can we called for a few seconds when site comes up.... Did not know that.

  1. User Clicks the background message.
  2. We are redirected to the Home page.
  3. Add this code on Home page (the page that you go to on click of the notification)

import {
  AppState,
} from 'react-native';
import notifee from '@notifee/react-native';
...
  const onAppStateChange = (nextAppState: string) => {
    if (nextAppState === 'active') {
      
      notifee.getInitialNotification().then(initialNotification => {
        console.log('getInitialNotification');
        if (initialNotification) {
          console.log(initialNotification);
        }
      }).catch((e) => {
        console.log(e);
      });
    }
  };

useEffect(() => {
    AppState.addEventListener('change', onAppStateChange);

    return () => {
      AppState.removeEventListener('change', onAppStateChange);
    };

  },[]);

from notifee.

Ehesp avatar Ehesp commented on July 20, 2024

Hey, what payload are you sending via FCM?

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024

Push example (Withouth data.notifee added)
asads

Now my code is:
In Index.js (I dont use this events for nothing, but i have to add to delete warnings)

import { AppRegistry } from 'react-native'
import { App } from './src/components/system'
import { name as appName } from './app.json'

import notifee from '@notifee/react-native'
import messaging from '@react-native-firebase/messaging'

notifee.onBackgroundEvent(async localMessage => {
  console.log('notifee setBackgroundMessageHandler localMessage', localMessage)
})

messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('messaging setBackgroundMessageHandler remoteMessage', remoteMessage)
})

AppRegistry.registerComponent(appName, () => App)

And App.js

  _enablePushNotifications = async () => {
    try {
      // CHECK PERMISSIONS
      const hasPermission = await messaging().hasPermission()
      if (!hasPermission) {
        await messaging().requestPermission()
      }

      // REGISTER FOR REMOTE NOTIFICATIONS
      await messaging().registerDeviceForRemoteMessages()

      // CREATE DEFAULT ANDROID CHANNEL ID TO LOCAL NOTIFICATIONS
      this.channelId = await notifee.createChannel({
        id: 'default',
        name: 'Default Channel'
      })

      // GET FCM TOKEN
      const fcmToken = await messaging().getToken()
      store.dispatch(notificationsOperations.updateFCMToken(fcmToken))
      console.log('FCM fcmToken:', fcmToken)

      // SET REFRESH TOKEN EVENT LISTENER
      this.onTokenRefreshListener = messaging().onTokenRefresh(fcmToken => {
        console.log('onTokenRefresh fcmToken:', fcmToken)
        store.dispatch(notificationsOperations.updateFCMToken(fcmToken))
        store.dispatch(notificationsOperations.postDeviceToken())
      })

      // REMOTE NOTIFICATION TAPPED WITH APP CLOSED OR IN BG
      const initialRemoteNotification = await messaging().getInitialNotification()
      if (initialRemoteNotification) {
        const data = JSON.parse(_.get(initialRemoteNotification, 'data.data', {}))
        if (data) {
          this._onNotifTapped(data)
        }
      }

      // REMOTE NOTIFICATION RECEIVED WITH APP FOREGROUND
      this.onMessageListener = messaging().onMessage(message => {
        const notification = _.get(message, 'notification')
        if (notification) {
          notifee.displayNotification({
            ...message,
            ...notification,
            android: { channelId: this.channelId },
            timestamp: Date.now().toString()
          })
        }
      })

      // LOCAL NOTIFICATION TAPPED WITH APP CLOSED OR IN BG (IS NOT BEING CALLED)
      const initialLocalNotification = await notifee.getInitialNotification()
      if (initialLocalNotification) {
        console.log('notifee getInitialLocalNotification notification', initialLocalNotification.notification)
        console.log('notifee getInitialLocalNotification pressAction', initialLocalNotification.pressAction)
      }

      // LOCAL NOTIFICATIONS TAPPED WITH APP OPENED
      this.onForegroundEventListener = notifee.onForegroundEvent(({ type, detail }) => {
        console.log('onForegroundEvent type: ', type)
        console.log('onForegroundEvent detail: ', detail)
        const data = JSON.parse(_.get(detail, 'notification.data.data', {}))
        if (type === EventType.PRESS && data) {
          this._onNotifTapped(data)
        }
      })
    } catch (e) {
      console.log('_enablePushNotifications e: ', e)
    }
  }

  componentWillUnmount() {
    this.onMessageListener && this.onMessageListener()
    this.onTokenRefreshListener && this.onTokenRefreshListener()
    this.onForegroundEventListener && this.onForegroundEventListener()
  }

  _onNotifTapped = notifData => {
    console.log('_onNotifTapped notifData: ', notifData)
  }

When user press on REMOTE NOTIFICATION i can get data and event with:

const initialRemoteNotification = await messaging().getInitialNotification()

When remote notification receive on foreground i get it with messaging onMessage event, and try to send local notification to show it:

this.onMessageListener = messaging().onMessage(message => {
        const notification = _.get(message, 'notification')
        if (notification) {
          notifee.displayNotification({
            ...message,
            ...notification,
            android: { channelId: this.channelId },
            timestamp: Date.now().toString()
          })
        }
      })

QUESTION: If i send LOCAL NOTIFICATION in foreground, when local notif is tapped on background or with app closed, i need similar behavior than with REMOTE NOTIFICATIONS, but app not open and const initialLocalNotification = await notifee.getInitialNotification() isnt called

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024

New update, i forgot add to AndroidManifest.xml this prop in activity: android:launchMode="singleTop"

this causes when you press a notification with the app in the background, the event "onNotificationOpenedApp" is not called.

however the messaging().getInitialNotification() event if it was called in its place, and left the app without redux state and in the initial navigation screen instead last loaded screen before go to bg.

With singleTop prop that problems are fixed. Now i need fix when i press notifee local notification in background or with app closed, app is not opened on android. How can i fix it? I need use notifee onNotificationOpenedApp and getInitialNotification events too for local notif with app closed or with app in bg like firebase messaging

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

I did mostly similar to your request with react-native-firebase only in https://github.com/mikehardy/rnfbdemo/blob/master/make-demo-v6.sh but this would be a great user utility for notifee. It has a combination of copied in items and shell-scripted-edited items, it's not dogmatic about getting it done. If you want to fork that off and have react-native-firebase-notifee.sh and put in whatever you have learned so far, I could put in what I'm learning (I'm going through the integration now) and I can work with the Invertase folks to finish the rest and we'll have the ability to give anyone a "throwaway example" project at will, that's easy to keep updated

from notifee.

netbull avatar netbull commented on July 20, 2024

@Ehesp that will be great!

Any plans to make onBackgroundEvent work on iOS?

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

@netbull there is no way, on iOS, if the app is force quit, for onBackgroundEvent to work, it is not possible on the platform. In all other cases, it does work?

from notifee.

netbull avatar netbull commented on July 20, 2024

Yes, it works. It works also in background /if the FCM message is Notification + Data/. Because of this the backend should send always Notification + Data as message in order to be sure that the notification will be always displayed, but this rise the question why then do we need Notifee library?

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

Foreground
Background
Force-killed

These are 3 different states, you specified force-killed. Data-only doesn't work force-killed

The SDKs will pop a local notification if you send notification + data, but then you have no control - your code doesn't execute. Notification + data payload are only delivered if user interacts with the SDK-popped local notification

You may not need the Notifee library, depends on your needs. Do what you need.

from notifee.

netbull avatar netbull commented on July 20, 2024

@mikehardy I need /for now/ 2 types of notifications. 1- not so important notifications, like memo reminders and 2- very important notifications for chat messages. When the user press over the notification, the app should open and route him to the corresponding Memo/Chat. Most of the logic /should a notification be send or when to which device/ is handled by the backend.

If I understood correctly, I should send always Notification + Data in order to be sure that the notification will be displayed. I am right?

Ooh, one more thing.. I use the library with react-native-firebase which is great, but if I use setBackgroundMessageHandler and include the option content-available in the FCM it just awakes the App, but the setBackgroundMessageHandler it's not called :/ And on the second message the handler is triggered.

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

In a force-quit situation I believe (that should always be read as: test it!) you have to send notification payload (with or without data) for it to show up. Although of course there are still other cases where it won't be delivered (APNs throttles you, the device power throttles you, etc). But to have a chance even, I believe it needs the notification payload.

Unknown about the background message handler, that's not expected. You might check that it really is very early in the startup sequence, make sure you test release build on a real device but plugged into Xcode and watching the console. Perhaps the app takes too long to startup before the method does it's work and you got power throttled? But then the second time since it's already alive it works? Just a hunch. If so, that can vary per-device even depending on device speed. I believe (read as: test it!) that Xcode logs on a connected device will show you if the handler was timed out?

from notifee.

netbull avatar netbull commented on July 20, 2024

@luisfuertes there is such listener in Notifee.

Here is what I use:
notifee.getInitialNotification() is used when the app is in killed state /not just background/ and the notification is pressed.
notifee.onForegroundEvent() is used with EventType.PRESS to handle pressed notifications when the app is in background or foreground mode.

It was a bit confusing from the docs /at least for me/, but finally I made it to work, without using messaging().onNotificationOpenedApp(remoteMessage => {})

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024

But if i send a local notification with notifee, kill the app, and open app tappin local notif, i think getInitialNotification and onForegroundEvent doesnt work in that flow

from notifee.

luisfuertes avatar luisfuertes commented on July 20, 2024

great i will try that

from notifee.

ANIBIT14 avatar ANIBIT14 commented on July 20, 2024

Hi, @luisfuertes the onMessage() is never triggered for me when I trigger notifications from firebase console, is there any specific case in which it will be triggered, I used the code that you specified above to create a local notification. Hoping you can provide some insight.

from notifee.

axeljeremy7 avatar axeljeremy7 commented on July 20, 2024

for ios has anyone try:

firebase.messaging().getAPNSToken();

and have issues triggering notifications.

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

@mahpat16 if a user taps a notification for me on android at least, with the app in the background, I do get an onBackgroundEvent with event type of "press", and since I have set the launch action to default, it pops my app to the front. As part of my onBackgroundEvent handler I also pull relevant info out of the "data" section of the notification that was tapped and I use that to navigate my app to a specific screen with specific data loading/loaded.

This sounds like what you are thinking, and it works for me. Am I perhaps misunderstanding your use case and there is a feature gap that isn't in my use case?

from notifee.

mahpat16 avatar mahpat16 commented on July 20, 2024

Yes this is what I am thinking. I am missing the specific callback or event where I can put the 'navigate' code in. I hope that makes sense, i.e. if you save the relevant data in the onBackgroundEvent handler. we still need another event that gets triggered where we can act on that data and navigate. Are you using regular react state change callback?

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

I use ReSub / https://github.com/microsoft/resub - and I have a "NotificationStore". In getBackgroundHandler I push the Notification object I get from the Notifee Event into NotificationStore as an "initialNotification" (the same place I put an actual initialNotification if one opens the app...). So now I have the data stuffed away. The NotificationStore then "triggers" which causes any mounted components to re-build state if they are listening to NotificationStore.

In my "Dashboard" screen which loads by default and thus is always mounted (via react-navigation) I have subscribed to NotificationStore events, so it gets the new initialNotification to handle (if there was one) and I go into my notification handling / maybe forwarding logic

In that way it all hooks up pretty well, with the same state handler shared between actual initial notifications and background notifications even.

There are of course infinite ways to do this. Although I think it's more popular to use redux, and now everyone is using hooks so my codebase seems prehistoric 😅

from notifee.

mahpat16 avatar mahpat16 commented on July 20, 2024

Thanks for the detailed explanation it certainly helps. Overall looks like you were able to leverage some of your existing triggers/event handler. And as you mentioned probably multiple other ways to achieve this. I guess adding this extra color to the notifee documentation would help the users. And I feel the original request to add a onNotificationOpenedApp still makes sense for users who dont have or want to use any other event/trigger system. Especially since FCM based notification already provides this trigger.

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

I agree it does seem like it would be a useful API to have

from notifee.

meliodev avatar meliodev commented on July 20, 2024

Yes this is what I am thinking. I am missing the specific callback or event where I can put the 'navigate' code in. I hope that makes sense, i.e. if you save the relevant data in the onBackgroundEvent handler. we still need another event that gets triggered where we can act on that data and navigate. Are you using regular react state change callback?

Hi @mahpat16, did you manage to navigate from onBackgroundEvent handler ? I am trying to do the same thing. But from index.js, we are outside of react context. Then I couldn't find any way to invoke react-navigation. As you mentioned, onNotificationOpenedApp would be helpful to be added on notifee. Is there any work around to accomplish this ?

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

You can always navigate in react-navigation can't you? I have no problem navigating directly (call setTopLevelNavigator as part of your first app render, call navigate where ever you need it...)

import { NavigationActions } from 'react-navigation';

let _navigator: any;

function setTopLevelNavigator(navigatorRef: any): void {
  _navigator = navigatorRef;
}

function navigate(routeName: string, params: any = {}): void {
  _navigator.dispatch(
    NavigationActions.navigate({
      routeName,
      params,
    })
  );
}

// add other navigation functions that you need and export them

export default {
  navigate,
  setTopLevelNavigator,
};

from notifee.

meliodev avatar meliodev commented on July 20, 2024

Hi @mikehardy. Thank you for your support. I really need this feature, I have just migrated to react-native-firebase v6 to use notifee.
Now to explain clearly my issue. onBackgroundEvent is mounted before my first app render (as suggested by notifee documentation). That's why I could not get a reference to my navigator.
Is there no issue to initialize onBackgroundEvent after rendering my app ?

Please find below my index.js

import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler'

import notifee, { EventType, AndroidImportance } from '@notifee/react-native'
import messaging from '@react-native-firebase/messaging'

//background & quit state: messages listener   
messaging().setBackgroundMessageHandler(onBackgroundMessageReceived)

async function onBackgroundMessageReceived(message) {
    const channelId = await notifee.createChannel({
        id: 'projects',
        name: 'projects',
        lights: false,
        vibration: true,
        importance: AndroidImportance.DEFAULT,
    })
    await notifee.displayNotification(JSON.parse(message.data.notifee))
}

notifee.onBackgroundEvent(async ({ type, detail }) => {
    const { notification } = detail
    //const { pressAction } = notification.android

    switch (type) {
        case EventType.PRESS:
            console.log('NOTIFICATION PRESSED !')

            // I want to navigate to a sepcified screen <--- Here is the issue

            await notifee.cancelNotification(notification.id)
            break
    }
})

AppRegistry.registerComponent(appName, () => gestureHandlerRootHOC(App));

from notifee.

mikehardy avatar mikehardy commented on July 20, 2024

Now to explain clearly my issue. onBackgroundEvent is mounted before my first app render (as suggested by notifee documentation).

I think you mean registered? React components are "mounted" in a view hierarchy, but handlers / callbacks etc are just registered. But! I understand what you mean. And sure. It's possible on Android to have onBackgroundEvent fire while no App is registered because of headless mode. On iOS it's not really possible as the whole App loads, there is no background.

That's why I could not get a reference to my navigator.
Is there no issue to initialize onBackgroundEvent after rendering my app ?

There is not, you will need some sort of storage state like redux or ReSub where onBackgroundEvent can store that it received something, and during app component mount you should check on your welcome screen whether anything was received that it needs to forward for

The same is true of dynamic links received in the background, notifications opening the app etc. Register handlers, have those handlers take note that they were called and store that in state, have your welcome screen check state and forward as necessary. That's the pattern I use anyway, works well for me?

from notifee.

github-actions avatar github-actions commented on July 20, 2024

Hello 👋, to help manage issues we automatically close stale issues.

This issue has been automatically marked as stale because it has not had activity for quite some time.Has this issue been fixed, or does it still require attention?

This issue will be closed in 15 days if no further activity occurs.

Thank you for your contributions.

from notifee.

pfinazzo avatar pfinazzo commented on July 20, 2024

@meliodev

I know this post is old, but I believe you have access to AsyncStorage within the onBackgroundEvent, and so you can save the stringified notification and then in App.js grab it in a useEffect for your internal page routing

from notifee.

billnbell avatar billnbell commented on July 20, 2024

Yeah that is what I said, but you can also just use notifee.getInitialNotification()

from notifee.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.