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

messaging.setBackgroundMessageHandler is not called in quit state on iOS #7389

Closed Ambreen-Kanwal20 closed 1 year ago

Ambreen-Kanwal20 commented 1 year ago

I use firebase/messaging in my react-native application to receive notifications from Firebase.

When a message is received, I'll process the data and update my badge count. On the Android device, everything works perfectly in the foreground, background, and terminated state. In iOS foreground and background are working fine. I quit the application, received a notification, setMessageBackgroundHandler is called and everything is working fine. As I open another application. My app notified me, but now setMessageBackgroundHandler is not being called.

When the app is terminated/quit, and any other application is running in the foreground. I receive a notification but the firebase setBackgroundMessageHandler event is not called. I've already added 'content-available': true in the notification payload but the event is not called when another application is in the foreground state. When I open my application, setBackgroundMessageEvent is called and another duplicate message is received in the app. Is this issue relatable to the resource-allocation priority of iOS?

Kindly help/guide me to fix this issue. Every help is appreciated.

yedi97 commented 1 year ago

Please try changing payload push fcm API from notification to data

Ambreen-Kanwal20 commented 1 year ago

Please try changing payload push fcm API from notification to data

Can you please explain it?

I'm using this node.js code for sending notifications.

const SEND_NOTIFICATION = async (message) => {
  // Send a message to devices subscribed to the provided topic.

  return admin
    .messaging()
    .send(message)
    .then((response) => {
      // Response is a message ID string.
      console.log("Successfully sent message:", response);
    })
    .catch((error) => {
      console.log("Error sending message:", error);
    });
};

 let payload = {
        notification: {
          title: meditations[i].notification_title,
          body: meditations[i].notification_description,
          image:
            process.env.CALMVIBE_S3_BASE_URL +
            "/" +
            meditations[i].images.medium,
        },
        data: {
          action_id: meditations[i]._id.toString(),
          type: NOTIFICATION_TYPES.meditation_added,
        },
        topic: meditation_topic,
        android: {
          priority: "high",
        },
        apns: {
          payload: {
            aps: {
              contentAvailable: true,
            },
          },
        },
        // apns: {
        //   payload: {
        //     aps: {
        //       "content-available": 1,
        //     },
        //   },
        //   headers: {
        //     "apns-priority": "5",
        //   },
        // },
      };

      await SEND_NOTIFICATION(payload);
yedi97 commented 1 year ago

Please try changing from:

notification: {
  title: meditations[i].notification_title,
  body: meditations[i].notification_description,
  image:
  process.env.CALMVIBE_S3_BASE_URL +
  "/" +
  meditations[i].images.medium,
},
data: {
  action_id: meditations[i]._id.toString(),
  type: NOTIFICATION_TYPES.meditation_added,
}

to

data: {
  title: meditations[i].notification_title,
  body: meditations[i].notification_description,
  image: process.env.CALMVIBE_S3_BASE_URL + "/" + meditations[i].images.medium,
  action_id: meditations[i]._id.toString(),
  type: NOTIFICATION_TYPES.meditation_added,
},
apns: {
  payload: {
    aps: {
     content-available: 1,
    },
  },
  "fcm_options": {
      "image": process.env.CALMVIBE_S3_BASE_URL + "/" + meditations[i].images.medium
  }
}

and update in RN change receive title, body from notification to data

mikehardy commented 1 year ago

If it is not a data-only message I do not believe .setBackgroundMessageHandler will ever be called, as it will never be a "background" (read as: data-only) message.

However - be very careful with this change! data-only messages have zero guarantees of delivery or timeliness and they will not all be delivered.

In the quit state on iOS I believe the SDK will pop up an unskinned notification if you send an FCM with a notification block, but your code will not execute at all unless the user interacts with the notification (thus bringing your app to the front, where it should have the relevant non-background message handlers called).

If you want different behavior you need a much tighter notification integration which may be achieved with something like notifee.app

I do not believe this is actionable in this repo - I do not believe there will be any changes here related to this issue, so please feel free to continue discussion but I'll close it as I think everything is behaving as expected for the various APIs, though this area is subtle and not easy to work with

mrkrand commented 1 year ago

In my case i used react-native-splash-screen.

In HeadlessCheck function i needed to return component that hides SplashScreen after that i got messaging().setBackgroundMessageHandler work on quit state.

Hope it helps somebody :)

import {useEffect} from 'react';
import SplashScreen from 'react-native-splash-screen';

const Headless = () => {
  useEffect(() => {
    SplashScreen.hide();
  }, []);

  return null;
};

export default Headless;
function HeadlessCheck({isHeadless}) {
  if (isHeadless) {
    // App has been launched in the background by iOS, ignore
    return <Headless />;
  }

  return <App />;
}
mdperez86 commented 3 months ago

In the quit state on iOS I believe the SDK will pop up an unskinned notification if you send an FCM with a notification block, but your code will not execute at all unless the user interacts with the notification (thus bringing your app to the front, where it should have the relevant non-background message handlers called).

Yes and this is unexpected since we don't have a way, from the server side, to know whether an app is quit or not (easy way). Meaning that the same message (intended to be a notification) is gonna be presented in two different ways. For example I'm using notifee to enhance foreground notifications, but since I don't have control over the unskinned notification shown by the SDK, the same notifications are shown when the APP is quit/background but with the default SDK configuration.

Do we have a way to enhance the unskinned notification shown by the SDK when the app is quit on IOS?