invertase / notifee

⚛️ A feature rich notifications library for React Native.
https://notifee.app
Apache License 2.0
1.86k stars 226 forks source link

Custom sound does not work when the app is in the background #927

Closed Hos1g4k1 closed 11 months ago

Hos1g4k1 commented 11 months ago

My team is using Notifee to show push notifications. We decided to customize the flow by introducing a custom sound for those notifications. After trying to make this work, I managed to implement a custom sound when the app was in the foreground, but I got the default sound when the app was in the background or killed state. After reading a few articles, I am confused about whether this is possible, especially on IOS.

I was researching answers given in this issue but I didn't managed to find the solution for this there - https://github.com/invertase/notifee/issues/155

Test flow was next -> log in in the app and gave permissions for notifications. Then, while I am in the foreground I sent one notification and it has the custom sound. Then, I go in the background. Send one more notification and it has the default sound. Same behaviour on Android and on IOS.

Lib versions:

My function for showing notifications looks like this

const displayNotification = async (message: FirebaseMessagingTypes.RemoteMessage) => {
  if (shouldDisplayNotification(message.data)){
    await notifee.requestPermission({ sound: true })
    await notifee.displayNotification({
      title: 'message.notification?.title',
      body: 'message.notification?.body',
      data: message.data,
      android: {
        pressAction: { id: 'default' },
        channelId: NOTIFICATION_CHANNEL_ID,
        sound: 'notification'
      },
      ios: {
        sound: 'notification.wav'
      }
    });
  }
};

Creating of Android channel

const createAndroidChannel = async () => {
  await notifee.deleteChannel(NOTIFICATION_CHANNEL_ID);
  await notifee.createChannel({
    id: NOTIFICATION_CHANNEL_ID,
    name: NOTIFICATION_CHANNEL_NAME,
    sound: 'notification'
  });
};

Initialisation of push notifications - getting all permissions

let listener = () => {};

export const initPushNotification = async () => {
  const authorizationStatus = await messaging().requestPermission();

  if (authorizationStatus === messaging.AuthorizationStatus.AUTHORIZED) {
    const token = await messaging().getToken();
    createAndroidChannel();

    listener();
    listener = messaging().onMessage((message: FirebaseMessagingTypes.RemoteMessage) => {
      ...code
      displayNotification(message);
    });

    onForegroundNotification();
    await onBackgroundNotification();
    return Promise.resolve(token);
  }

  return Promise.resolve(null);
};
mikehardy commented 11 months ago

I'm not sure I'll have time to answer the question in general but I certainly spend no time examining things on old versions:

"@notifee/react-native": "5.7.0", "@react-native-firebase/messaging": "14.2.4",

At least for android - for iOS it has been a while since I looked so I'm not sure - once you create a channel you never get to update the channel settings other than the text (name + description), even if you delete/recreate the channel. The user is in control all of non-text parts of the channel post-creation. So that may have an effect on your test scenarios

You don't include the JSON of the FCM you send that would trigger a notification. If you're not specifying the correct android channel id, for instance, then you won't get the one you attempted to configure with custom sound (https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#AndroidNotification) - apple has something similar you put in the ApnsConfig payload section https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc / https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#ApnsConfig

Hos1g4k1 commented 11 months ago

Thank you for fast response.

I will update Notifee version on the newest one. After that, I will test again and post the results here.

You don't include the JSON of the FCM you send that would trigger a notification.

I didn't provide FCM JSON because I didn't use it for this feature. What I am trying here to accomplish is to set the sound of all notifications from React Native code. I am familiar with the fact that we can do that if we add "sound": "someSound" into the FCM JSON, but that's not what I am trying to do. I read the documentation and didn't find the article telling me this cannot be done. If I am wrong, please correct me.

mikehardy commented 11 months ago

I didn't provide FCM JSON because I didn't use it for this feature. What I am trying here to accomplish is to set the sound of all notifications from React Native code

Then your example is incomplete and doesn't conform to philosophy of https://stackoverflow.com/help/how-to-ask / https://stackoverflow.com/help/minimal-reproducible-example - specifically:

onForegroundNotification(); is not defined

I assumed you were sending FCM JSON since I could not see any other location where you would construct a notification and post it. If you are not, please take care to provide a simple, complete example that shows the problem. Probably best to reduce the entire thing to one single simple App.js where you forget about what your app is currently doing and just try to isolate + demonstrate this problem, so it's easy to discuss with no missing parts.

Hos1g4k1 commented 11 months ago

I think we just have a misunderstanding here about what and how it's done. So, we have the system for handling push notifications in all three states - foreground, background and killed. And there everything works as expected. Notifications are received and handled properly.

The part where I think we don't understand each other is how we are handling background notifications. There, we are sending FCM JSON from our backend. That FCM JSON doesn't have "sound" field because I understood from the documentation that that's not necessary. So, in the code I provided I am trying to set custom sound for my background notifications on the front side. Is that possible at all?

Now, we want to introduce the custom sound for these notifications. I did a research on this topic and found Notifee's articles how that should be done. I will reference them here:

I implemented everything like in these examples. The sound files are in the right folders, and the code is 1-1 match. I provided that code in my first message.

export const onBackgroundNotification = async () => {
  if (!messaging) return;

  const message = await messaging().getInitialNotification();

  if (message) {
    const { data } = message;
    handleNotificationTap(data);
  }

  messaging().onNotificationOpenedApp(({ data }) => {
    if (data) {
      handleNotificationTap(data);
    }
  });
};

Here, they said that we need "sound" field inside of a FCM JSON in order to play sound when the notification is received in the background - https://medium.com/@osamakhann118/custom-sound-for-react-native-push-notification-firebase-push-notification-sound-notification-f2b5ef5d00af . Is that true or not? Do I need "sound" field or I can set this custom sound without it?

This is a handler for the background push notifications. So, there we are just receiving notifications, extract the data and handle them. Nothing too special. So, the main question is "Can we implement custom sound for the background push notifications on the frontend side without using of the FCM JSON?".

Sorry if I didn't form the question well in the first try. I did my best to resolve that problem now.

mikehardy commented 11 months ago

In background states the underlying firebase-ios-sdk and firebase-android-sdk libraries will handle notification blocks before control flow ever reaches any other code here (including Notifee, unless you have a notification extension handler implemented...)

So I expect you will need to set the sound options in the FCM JSON and that seems to be confirmed by your experimental results

What happens when you use the sound fields I reference in the FCM JSON documentation upstream?

Hos1g4k1 commented 11 months ago

I implemented this using FCM JSON - added sound property and everything works fine. Thanks for the assistance.

arunandroapps commented 5 months ago

@Hos1g4k1 can you share the FCM JSON sent from the server side???