22

When using Google push notifications, I am allowed to specify a collapse_key value so a device will not receive multiple notifications of the same collapse_key. Does APNS have a similar feature or does anyone know a way to emulate this functionality?

Kara
  • 5,650
  • 15
  • 48
  • 55
David
  • 812
  • 1
  • 10
  • 26
  • We're just starting to investigate this, but sending a "silent notification" using the "content-available" APNS key would, theoretically, wake up your app in the background for a moment, let you consume existing messages, and issue a new "local notification" with the new/updated content. You could hide the actual message in a custom key, and use it when issuing the local notification. https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW6 – Dave Martorana Apr 18 '16 at 20:33
  • As of iOS 10 there is an exact equivalent. See my answer http://stackoverflow.com/a/39666412/365580 – Doody P Sep 23 '16 at 21:16

5 Answers5

29

As of iOS 10 and using the HTTP/2.0 APNS API, you can specify apns-collapse-id header and handle the collapse logic in your app.

Collapsed notifications will appear as one single notification on the device that keeps updating with new data. Each time a notification is updated it is pushed to the top of your unread notifications.

Description of apns-collapse-id taken from https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html:

Multiple notifications with same collapse identifier are displayed to the user as a single notification. The value should not exceed 64 bytes. For more information, see Quality of Service, Store-and-Forward, and Coalesced Notifications.

and from https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1:

When a device is online, all the notifications you send are delivered and available to the user. However, you can avoid showing duplicate notifications by employing a collapse identifier across multiple, identical notifications. The APNs request header key for the collapse identifier is apns-collapse-id and is defined in Table 6-2.

For example, a news service that sends the same headline twice in a row could employ the same collapse identifier for both push notification requests. APNs would then take care of coalescing these requests into a single notification for delivery to a device.

Kevin Cooper
  • 4,244
  • 4
  • 33
  • 50
Doody P
  • 2,645
  • 1
  • 17
  • 17
6

With iOS 10 there is a new "apns-collapse-id" which looks like it will handle this sort of need. If you have an Apple developer account you can look at the WWDC 2016 notification session videos (707 intro video https://developer.apple.com/videos/play/wwdc2016/707/).

chadbag
  • 1,768
  • 2
  • 18
  • 34
1

Doody P's answer works for remote notifications, but there is also an equivalent for locally triggered notifications: when you create your UNNotificationRequest, you can set the identifier parameter to whatever you had been using as a collapse key. After being triggered, the push notification will show only the latest version that you sent with that identifier.

(We send push notifications silently through APNs and then retrigger as local notifications, because we need to make sure that our users are logged in.)

There are handy code examples & demos of managing delivered notifications in this WWDC talk - the key section is from ~18:00 - 21:00.

Hannele
  • 7,820
  • 5
  • 46
  • 64
  • If the user has force closed the app/disabled background app refresh, your app won't launch for you to check if a user is logged in, how do you handle that situation? @Hannele – Patrick Aug 30 '20 at 02:36
  • @Patrick oof that is a good question. It's honestly been ages and I don't really don't know the best answer :/ – Hannele Sep 30 '20 at 16:09
0

If APNs attempts to deliver a notification but the device is offline, the notification is stored for a limited period of time, and delivered to the device when it becomes available.

Only one recent notification for a particular app is stored. If multiple notifications are sent while the device is offline, each new notification causes the prior notification to be discarded. This behavior of keeping only the newest notification is referred to as coalescing notifications.

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html

So there's no need for collapse_key in iOS.

FYI, collapse_key is only useful when the device is offline/inactive:

This parameter identifies a group of messages (e.g., with collapse_key: "Updates Available") that can be collapsed, so that only the last message gets sent when delivery can be resumed. This is intended to avoid sending too many of the same messages when the device comes back online or becomes active (see delay_while_idle).

https://developers.google.com/cloud-messaging/server-ref#downstream

UPDATE:

For both iOS and Android (using collapse_key), if the device is offline (ie the Apple/Google push server cannot reach it), the push server overwrites any previous notification, and only keeps the last one.

If the device is online, then I guess it's up to you to do whatever you want with the received notification. At least in Android you can decide whether you want to "pile things up", whether you want to overwrite any previous notification in the notification area, or whether you want to overwrite any previous notification of the same type.

NotificationManager notificationManager = ...;
String appName = ...;
NotificationCompat.Builder builder = ...
// Always use the same id, so only the last notification will be displayed in the notification area.
int notId = 0;
// Always use a different id, so all notifications will pile up in the notification area
notId = new Random().nextInt(100000);
// Uses the type of notification as id, so you'll only have up to one notification per type
// in the notification area. It's like using collapse_key, but on the app itself.
// That type should should be some additional data in the notification you sent.
notId = notificationType;
Notification notification = builder.build();
notificationManager.notify(appName, notId, notification);
user276648
  • 5,199
  • 5
  • 51
  • 79
  • This only occurs when the iOS device is offline. If the user has not checked their device in a while but the device is online (even when the screen is asleep), the notifications will pile up (at least when I first posted this, this policy may have changed with newer iOs versions). The Google collapse_key may only work when the device is inactive, but I believe this covers when the screen is sleeping as well which is the scenario my question was referring to. – David Jul 28 '15 at 17:18
  • @David: see updated answer. I'm not sure how things work exactly on iOS though, so I don't know if something similar to what I wrote for Android is possible. – user276648 Jul 29 '15 at 02:11
-1

There is no such feature in iOS. However, since push notifications are sent by a server that is in your control, you can keep track of which notifications you've sent to a particular device, and decide whether or not to send new ones. In other words, you put the logic in your server code, not your iOS app code.

jsd
  • 7,565
  • 5
  • 24
  • 42