For Android the solution is pretty easy, Notifo is able to send firebase data messages, which are non-collapsible by default and have a default time-to-live period of four weeks, so we can receive all offline messages. But for iOS Apple will only store the most recent notification sent to a device on the APNs servers. So turns out for iOS we need a completely different custom solution.
First, we need to send different types of messages for Android and iOS. Android will need data messages and iOS will need notification messages. It is because iOS will treat data messages as silent messages and Apple does not guarantee the delivery of silent messages and put other restrictions on them.
In order to send platform-specific message payload, we need to use Firebase HTTP v1 API. Then we can use a message format like in the example below.
{
"message": {
"token": "<DEVICE TOKEN>",
"android": {
"data": {
"title": "Title Android",
"body": "Body Android"
}
},
"apns": {
"payload": {
"aps": {
"alert": {
"title": "Title iOS",
"body": "Body iOS"
},
"mutable-content": 1
}
}
}
}
}
Second, when the last notification gets delivered after the device will back online we will send a delivery report to Notifo backend using a unique trackingUrl
, then the Notifo backend will schedule a background/silent notification to wakeup the iOS device (no more than once per 30 minutes). This background notification will initiate fetch and show pending offline notifications as local notifications on the iOS device.
Apple doesn’t provide any official method to know when a Push Notification has been delivered to the user’s device. We are using UNNotificationServiceExtension for that purposes. It turns out to be a viable solution, the only limitation is we have 30 seconds to send the delivery report to Notifo backend, but that feels more than enough. For this solution, there is included mutable-content
parameter in the payload example above.
For tracking/storing delivered notifications locally we are using Xamarin.Essentials.Preferences
(that uses iOS UserDefaults
on the iOS platform). In order to be able to share data between a host app and its app extension, we need to configure an app group capability.
Name convetion for app group is group.{app-bundle-id}.notifo
.