We are building a react-native IOS application, which uses FCM at the backend and notifee at the front end. Everything works, but there are often times when a FCM-data-push is sent but the notification is not shown on IOS if the app is in killed state. Following is the message object that we are sending to the FCM server through firebase-admin's node package.
const message = {
token: fcmToken,
data: prepared,
android: {
priority,
},
apns: {
payload: {
headers: {
'apns-priority': 10,
'apns-push-type': 'background',
},
aps: {
'content-available': 1,
},
},
},
};
It is required to register a task that runs in the background while the app is killed then the registered task handle notification event listens and pushes notification.
Consult this package for background task - https://www.npmjs.com/package/react-native-background-task
Related
TL;DR
I'm detecting uninstalls using FCM. If I receive a NotRegistered token on sending notification, I assume that the app has been uninstalled.
Everything works fine with Android, while on IOS I'm always getting a success response, even if the app has uninstalled for days.
More info
I have read that it is possible to detect uninstalls using APNs feedback Service, where Apple reports any inactive tokens.
Also I read on Firebase official documentation that:
content_available - On iOS, use this field to represent content-available in the APNs payload. When a notification or message is sent and this is set to true, an inactive client app is awoken, and the message is sent through APNs as a silent notification and not through the FCM connection server.
In order to send notifications via APN, I have tried to send push notifications using content_available: true, but I cannot reproduce a NotRegistered token error on IOS. It still returns a success message.
I'm sending notifications using sendMulticast. my payload:
const payload = {
notification: {
title: text,
},
android: {
priority: "high",
ttl: 60 * 60 * 1,
collapseKey: "yo",
notification: {
channel_id: 'YO',
tag: userDoc.id,
},
},
apns: {
payload: {
aps: {
sound: "reminder.caf",
"content-available": 1,
}
},
headers: {
"apns-collapse-id": "yo",
"apns-priority": "10"
}
},
priority: 10
}
I also cannot reproduce a NotRegistered token response via an HTTP request:
curl -X POST \
https://fcm.googleapis.com/fcm/send \
-H 'authorization: key=server_key_here' \
-H 'content-type: application/json' \
-d '{
"to": "fcm_token_here",
"priority": "high",
"content_available": true,
"notification": {
"empty": "body"
},
"data": {
"key1": ""
}
}'
Bottom Line
1. How do I detect IOS uninstalls using FCM?
2. And if it's not possible, how can I detect uninstalls on IOS?
Well, depends on your demand. Your questions's answer is slient push not normal push.
A background notification is a remote notification that doesn’t display an alert, play a sound, or badge your app’s icon. It wakes your app in the background and gives it time to initiate downloads from your server and update its content. Apple Document
Important
The system treats background notifications as low priority: you can use them to refresh your app’s content, but the system doesn’t guarantee their delivery. In addition, the system may throttle the delivery of background notifications if the total number becomes excessive. The number of background notifications allowed by the system depends on current conditions, but don’t try to send more than two or three per hour.
Silent push notifications will not work when the device is in “Low
Data Mode“.
Slient Push Notification Payload Example.
{
"aps" : {
"content-available" : 1
},
"acme1" : "bar",
"acme2" : 42
}
You have to use "content-available" : 1 in payload for slient push.
On the other hand, if your client running on iOS 12.3 or later Deletions metric
I am trying to implement cache meachanism for FCM on IOS. I am using Xamarin Forms with CrossGeeks FirebasePushNotificationPlugin
Push notification service works fine. I am using payload pattern as below
{
"data": {
"message" : "my_custom_value",
"other_key" : true,
"body":"test"
},
"notification": {
"body" : "hello",
"title": "firebase",
"sound": "default",
"content_available" : true
},
"priority": "high",
"condition": "'general' in topics"
}
Above pattern appears delivered notification as alert on IOS main screen.
I have written a Dependency Service for getting undeleted or unopened accumulated notifications when app starts. Dependency Service include below codes
await UNUserNotificationCenter.Current.GetDeliveredNotificationsAsync();
When I use above payload, I can get accumulated notifications. But when I use payload pattern as below, I can not.
{
"data": {
"message" : "my_custom_value",
"other_key" : true,
"body":"test"
},
"notification": {
"content_available" : true
},
"priority": "high",
"condition": "'general' in topics"
}
Actually I would like to send 2 payload types for every notification for my cache mechanism because of prevent the user's delete action. After that, I would like to show cached notifications without any lost in my app's notification page.
Shortly my question about "I am not getting silent payload values from UNUserNotificationCenter this approach is possible or not?"
Or can I prevent the user's notification delete action from IOS main screen when my app is terminated.
Note: My minimum OS version is 10.0 in info.plist
Thank you in advance.
I created a sample Cordova app which is using "phonegap-push-plugin".
That app doesn't have any complexity. On "deviceready" I run the plugin initialization code as shown here:
var push = PushNotification.init({android: {}, ios: {
sound: true,
alert: true,
badge: true,
categories: {
invite: {
yes: {
callback: 'accept',
title: 'Accept',
foreground: true,
destructive: false
},
no: {
callback: 'reject',
title: 'Reject',
foreground: true,
destructive: false
},
maybe: {
callback: 'maybe',
title: 'Maybe',
foreground: true,
destructive: false
}
},
delete: {
yes: {
callback: 'doDelete',
title: 'Delete',
foreground: true,
destructive: true
},
no: {
callback: 'cancel',
title: 'Cancel',
foreground: true,
destructive: false
}
}
}
}})
push.on('notification', data => {
console.log(data.message);
console.log(data.title);
console.log(data.count);
console.log(data.sound);
console.log(data.image);
console.log(data.additionalData);
})
push.on('emailGuests', data => {
console.log('I should email my guests');
});
push.on('snooze', data => {
console.log('Remind me later');
});
push.on('registration', data => {
console.log(data.registrationId);
console.log(data.registrationType);
});
push.subscribe('xx', console.log)
And this is the log output to console:
=> Successfully subscribe to topic xx
// The first run (after app install) will ask for permissions. If I click allow the lines below are printed to console.
=> dCAtjhCFBcU:APA91bG90c8VhNl_BzZ-2e9fmq_9fN6jfrRNJ1LPCRIpKnZ-AG-eLY4xtX84oJRZBh2D....KtNNQ35GM8ubPF5zr8HqeB6jffs
=> FCM
In order to push I'm sending the following payload to the Legacy Server https://fcm.googleapis.com/fcm/send.
{
"priority": "high",
"to": "/topics/xx", // I tried this but I also tried to specify the device token received upon "registration" event. I did this using to:<device_token> and also using registration_ids: [<device_token>].
"notification": {
"title": "My Message",
"body": "My Message Body",
"badge": 1,
"content-available": "1", // I tried with and without
"category": "identifier", // I tried with and without
"thread-id": "id", // I tried with and without
"sound": "default",
"icon": "default"
},
"data": {
"title": "A short string describing the purpose of the notification",
"body": "The text of the alert message",
"clubId": 1000
},
"notId": 1,
"custom_key1": "value1",
"custom_key2": "value2"
}
Note: I tried every combination possible in what concerns the app state: App in background; app closed; app in foreground; The event "notification" has never fired and the push notification was never received.
The request sent to the FCM server returns a message id when I use the topic (which is understandable since other devices subscribe the topic). For that reason my android that has subscribed to the same topic receives the message. The iOS in the other hand receives nothing!
{
"message_id": 5059997308576486332
}
If I try to specify the token that I received upon registration, I will get a slightly different message. Most of the time the token received upon registration works and the results will contain a string id. But this is temporary since a few minutes later the token become "NotRegistered".
{
"multicast_id": 88880398234xxxxx7,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{
"error": "NotRegistered" // <-- This happens after a few minutes. I have to delete the app and reinstall it in order to get a new token.
}
]
}
This is the build configuration
Notifications are correctly enabled on my iOS device. What am I missing?
Updated:
Accessing Apple's APN directly (yup... no FCM!)
I would like to send my push notifications through FCM but in order to determine the cause of the issues described above, I decided to try APN directly. To do this, I had to remove the from the app's config.xml, so phonegap-push-plugin can obtain a token from APN and not from FCM.
Now, using the new token and a server that uses node-apn module to communicate with APN server, I'm able to send push notifications to my iOS app. The downside of this, is that I lose the ability to push to topics since this is a FCM only feature.
The only thing that I still don't know is how to use the topic to target devices in the APN network, that are subscribed by the push.subscribe() method.
Checkout my issue here.
Any help on this too?
So, turns out there's an issue with the push plugin.
This issue only impacts users on iOS device apps that use the FCM.
If you use the APNs it works.
You can check my answer in here: https://github.com/phonegap/phonegap-plugin-push/issues/2644#issuecomment-445346335
And my initial issue reporting in here:
https://github.com/phonegap/phonegap-plugin-push/issues/2613
I'm using the phonegap-plugin-push on my ionic3 app and I've been facing this issue with the iOS platform (android is ok). When the app is in background/foreground everything works as expected. When the app is not running however, I get the message on the notification tray but neither tapping the notification or the app icon triggers the on('notification') event, it simply runs and ignore the incoming notification.
I'm using the { ... content-available: 1} in the aps json message as suggested by the docs, but it doesn't seem to have any effect (though, it does have effect on Android), the ionic app itself never gets the message even though the device received it and displayed it on the tray.
Bellow, I show my configurations and a sample message sent to the push services. If anyone have any idea on how to sort this out will be appreciated, I've tested on ios 8.x and ios 11.x, both have presented the same behavior.
const options: PushOptions = {
android: {
senderID: '*************',
icon: 'ic_stat_ic_notification'
},
ios: {
alert: 'true',
badge: 'true',
sound: 'true'
},
windows: {}
};
platform.ready().then(() => {
push.on('registration').subscribe((data: EventResponse) => {
// register data.registrationId
});
push.on('notification').subscribe((data: EventResponse) => {
alert(data.message)
});
});
Sample message:
{
"aps": {
"alert": "This is a Push",
"badge": 1,
"content-available": 1
},
"payload": {
"type": "news"
}
}
This is too long of a comment. It's more of an indirect answer.
1) or the app icon triggers the on('notification') event <-- that's expected. Imagine your app just received 10 notifications. How should it know which notification you intended to open?
2) neither tapping the notification <-- this should trigger something in your code. Do you have didReceiveNotificationResponse implemented? Does that get called? Or does your didFinishLaunching get launched with a remoteNotification key? How about your application(_:didReceiveRemoteNotification:fetchCompletionHandler:) does that get called?
I'm working with firebase to add push notification feature to an app, everything is fine with the push notification it self but in some state of the app the push notification is not receive.
Foreground / Background:
{
"data":{
"title": "title",
"message": "message"
},
"content_available":true,
"priority":"high",
"registration_ids":[
""
]
}
The problem comes when the app is killed by the user, I send the same http request but the app didn't receive the remote notification.
I was testing with the console on firebase and when the app is killed the notification it's receive but I couldn't replicate the console request to http request
this is the content of notification when I made it through firebase console
[
"google.c.a.c_l": label optional,
"google.c.a.e": 1,
"google.c.a.ts": IntValue,
"google.c.a.udt": 0,
"gcm.n.e": 1,
"aps": {
alert = {
body = mensaje;
title = title;
};
},
"google.c.a.c_id": IntValue,
"gcm.message_id": 0:1502103735577088%9218dc2f9218dc2f
]
This is how iOS works, basically. When your app is killed by the user, it no longer receives background notifications.
Here's a somewhat-old-but-still-accurate link with some more detailed information: http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/