Hi,
I have a couple of issues to address. Initially I let Notifee to handle the notification display for all foreground and background notifications on iOS (note: with actions) as follows:
notifee.onForegroundEvent(async ({type, detail}) => {
handlePushNotificationActions(type, detail);
});
},
notifee.onBackgroundEvent(async ({type, detail}) => {
handlePushNotificationActions(type, detail);
});
},
await notifee.setNotificationCategories([
{
id: "some_category_id",
actions: [
{
id: "some_action_id",
title: "some_action_title",
},
],
},
]);
const handlePushNotificationActions = (type, detail) => {
const {notification, pressAction} = detail;
if (
type === EventType.ACTION_PRESS &&
pressAction.id === "some_action_id"
) {
// Handle action here
}
};
Since I am using Notifee to display all the notifications, I send data-only payload from my Node server:
```{
token: fcmToken,
data: {
notifee: JSON.stringify({
title: "Data Payload",
body: "Some body",
ios: {
categoryId: "some_category_id"
},
data: {
key: "value",
},
}),
},
apns: {
payload: {
aps: {
"category": "some_category_id"
},
},
},
};
However my app cannot receive any push notifications if the following 3 conditions are met:
1. My iPhone is in low power mode
2. My phone is unplugged (not charging)
3. The app is killed
I tried adding `contentAvailable: true` to the payload but I still did not receive any push notification.
{
token: fcmToken,
data: {
notifee: JSON.stringify({
title: "Data Payload",
body: "Some body",
ios: {
categoryId: "some_category_id",
},
data: {
key: "value",
},
}),
},
apns: {
headers: {
"apns-priority": "10",
},
payload: {
aps: {
contentAvailable: true
},
},
},
To be able to receive push notification in above 3 conditions, I had to add the notification payload when sending push from server:
{
token: fcmToken,
notification: {
title: "Notification Payload",
body: "Some body",
},
data: {
notifee: JSON.stringify({
title: "Data Payload",
body: "Some body",
ios: {
categoryId: "some_category_id"
},
data: {
key: "value",
},
}),
},
apns: {
payload: {
aps: {
"category": "some_category_id"
},
},
},
};
```
This causes another issue, now both the FCM and Notifee libraries show two notifications (one each) if the app is in the background (not killed).
If the app is killed, another issue arises - by adding the notification payload when sending push from server, Notifee's onBackgroundEvent will not be called anymore. It looks like the FCM library is handling the push notification instead of Notifee. As I mentioned earlier I need to create action button for my push notification. I then add "category": "some_category_id" in the apns payload. The push notification received is now showing the action but I do not know how can I handle the callback when the action button is clicked?
The Firebase messaging library has this callback when the push notification is tapped:
messaging().onNotificationOpenedApp((remoteMessage) => {
})
However I need to handle the click action callback. There is no way for me to get the pressAction type like the notifee.onBackgroundEventcallback.
Any idea on how to fix these issues?
I think if we're able to fix issue 1, we won't have to deal with 2 and 3. Thanks!
I believe it is 'content-available: 1' ?
(sorry to be so brief! It's 2020 and I'm also in virtual school with my kid helping :sweat_smile: - but that may break through most/all of the problems here)
No worries! 馃槃 Thanks for your quick reply! I just tried 'content-available: 1' and it didn't work either. Everything works if I get out of low power mode though.
If it helps, when I send both notification+data payloads from server:
Looks like the data payload is ignored completely in low power mode.
I believe that is correct, low-power mode means data-only is not ignored but it is queued. You should receive the message when the phone has full power again or if the user opens the app
Mixed payloads mean that you will get firebase-ios-sdk processing the notification via some hooks where your code never gets control in order to show the notification, and then either when the user taps on the notification or (if fully powered up with regular delivery I suppose) you will also have your data handler called.
I don't like the iffy-ness of mixed payloads since I'm not in 100% control of notification display but I have easier constraints on message delivery, they can wait until the user is not low power or in the app. If you have tighter constraints doing a mixed payload but knowing that for those mixed payload JSON you should perhaps do something with state internally but not show a notification might work for you.
Note that you are never receiving two JSON chunks from the cloud. I believe you are just seeing different handlers called under different situations, where apple is assuming that in low-power mode a data-only notification isn't worth spending power on.
I have been playing around with this for 3 weeks now and agree that content-available: 1 is not enough. This is the request I would assume should work:
message: {
data: {
body: message,
type: message_type
},
apns: {
payload: {
aps: {
"content-available": 1
}
}
},
token: device.token
}
@khiawyen I agree that the notification payload is the only method that seems to work consistently. To avoid your problem of duplicate notifications use apns directly. This can be achieved by using the apns > payload > aps > alert key. For a detailed explanation of what customizations are available have a look at the apple push notification documentation. Here is my above request using apns directly:
(snake case because it is ruby)
message: {
data: { # this can be used for forground message handling and for android in general
body: message,
type: message_type
},
apns: {
payload: {
aps: {
category: "custom_category", # This will work with categories that were defined somehow. I use notifee for that.
alert: { # overwrites the data payload in case of iOS
body: message
}
}
}
},
token: device.token
}
We are not live yet, so I only tested this in a dev environment.
Based on the apple documentation regarding background app update it appears that aside from content-available it is also important to set the headers: apns-priority and apns-push-type. I tried that but it made no difference. Bottom line I don't think this is really a bug from firebase or apns but expected behavior from apns, the docs state:
When a device receives a background notification, the system may hold and delay the delivery of the notification, which can have the following side effects:
When the system receives a new background notification, it discards the older notification and only holds the newest one.
If something force quits or kills the app, the system discards the held notification.
If the user launches the app, the system immediately delivers the held notification.
...
Your app has 30 seconds to perform any tasks and call the provided completion handler
For me this means that the whole data notification concept on iOS is relatively brittle and is not a viable option for 100% notification delivery.
That is correct. Data only is 'best effort' only. It should be used for refresh type things that speed up the experience on launch like pre cache, or for work that may be missed without problem.
@mikehardy it does not actually really mention this anywhere on notifee or react-native-firebase. A lot of issues regarding background notification for iOS that you commented on I think might benefit from this information, in addition to the docs i.e. if you want reliable notifications don't use data, use apns alerts. At the moment the general notion I got from all the issues was: if you want iOS notification with notifiee then add content-available.
indeed - the platforms have evolved a bit underneath us, as well as my/our understanding of it. All the docs pages have edit buttons top right, anywhere you can think of that it would be useful if you want to submit a PR that could help a lot. Invertase - same team behind this module, react-native-firebase and FlutterFire (new work for us/them) have added this here https://firebase.flutter.dev/docs/messaging/usage/#low-priority-messages
it is probably the best summary of current knowledge (as it is the freshest chunk of docs written on the topic)
Most helpful comment
(sorry to be so brief! It's 2020 and I'm also in virtual school with my kid helping :sweat_smile: - but that may break through most/all of the problems here)