Notification service extension - hide previous notifications - ios

Take, for instance, a messaging app that only presents notifications with in this format: You have X new messages
When the user receives a message, the app will present a notification: You have 1 new message
When it receives a second message, a new notification will be shown:You have 2 new messages
Ideally, after receiving the second notification, the first one should be cancelled/hidden, as the user has only 2 new messages, instead of 1 + 2.
If notifications are locally presented using UserNotifications, to fix that you simply have to use the same identifier when creating the UNNotificationRequest for both notifications.
Is there a way to achieve the same when using a Notification Service App Extension?

This can be done by modifying the notification in the server side. There's a header named apns-collapse-id that you can set. More info on how to do so is available in this article by Apple.
All notifications with the same header will be coalesced - that is, only the newest one will be shown, the previous will disappear.

Related

Only Allow One User To Click Push Notification

I want to send all users of my app a Push Notification that will bring them to a certain page in the app.
However, I only want one user to be able to tap it and go to the page, and when one user loads the page that the push brings them into, I want to silently remove the push from all other users.
Is this possible to do? I'm not sure how to grab all sent push notifications, whereas the UNUserNotificationCenter only grabs pushes sent on that device.
Thank you in advance!
I believe that this is possible if you use silent notifications.
Send a silent notification of type A.
All devices receive a type A notification and create local notifications in their UI.
A user press this local notification and load the page from the server.
Application of that use on the click / load event will send some request/event to your server that someone access the link.
Your server will send another silent notification of type B.
All devices receive the type B notification and use the code of the links to discard the type A notification from their own notification center.
Here are relevant posts of clearing notifications:
all the notifications of your application:
iOS application: how to clear notifications?
a specific notification:
https://stackoverflow.com/a/6341476/944070
Possible problems / Issues:
Between the user's click step 3 and step 6 it may take some time if you consider the push delivery times, so someone else may press the link. It's not instant. This can become worse in bad network conditions.
It may be annoying to the users that get a beep on their devices and the notification at last cleared because someone else was faster.
You cannot remove a push notification once it has been sent.
Although you could update the App badging by sending another push to reset the badging to zero. While this won't remove the previous push message, it can hide the red badging on the App icon.
You can simply remove the notification by
Sending the badge count as 0
APNS payload will be :
{
"aps" : {
"alert" : "",
"badge" : 0,
"sound" : "bingbong.aiff"
}
}
If you want to remove or decrease badge count number then you can do it easily with
UIApplication.shared.applicationIconBadgeNumber = max(UIApplication.shared.applicationIconBadgeNumber - 1, 0)
If you want to remove a single notification from notification center then, you can do it by using UNUserNotificationCenter in iOS 10 and above.
UNUserNotificationCenter object manage all notification-related behaviors in app or app extension.
You can removes the specified notification requests from Notification Center by using :
func removeDeliveredNotifications(withIdentifiers: [String])

How to restrict the some iOS Push Notification message to user while app is background?

I am working on iOS application, it contains one task about to restrict the some Push notification to user when our app is in background.
consider this example if user have 4 types push notification of our
project like:
Some one sent Friend request.
Some one like his comment.
Some one share his comment.
Some one send message to user.
if user did want to push notification for Type 1 and 4 without using of server side script while our app is in background?.
Note: how to handle the push notification message of our application before it add in notification centre?

Apple Multiple Push Notifications not visible in Notifications Tray

I basically want to make multiple push notifications in the same application visible in the notification tray in iOS.
This scenario works if my data is on while push notification is triggered via APNS, but only the latest one is received in case I am offline and come back after a while. This functionality is affirmed by APNS documentaion.
However, this is what worked in WhatsApp:
Turned Data Connection OFF
Sent some messages to WhatsApp
Turned Data Connection ON
Saw multiple push notifications received in Apple's Notification Tray
How's this scenario working? Can I use APNS for this? If yes, then how?
See this sample image of multiple Push Notifications in WeChat.
Like you wrote in your question, this is mentioned in the Apple Docs:
If you are sending multiple notifications to the same device or
computer within a short period of time, the push service will send
only the last one.
Link
The only scenario that what you're describing will work is if your whatsApp was open in the background while getting those push notifications. That way whatsApp will handle them as local notifications and will present all of them in the notification center. If whatsApp was closed you'd get only the last notification like any other app.
You can easily test this:
Terminate whatsApp and turn on Airplane mode.
Send your device 5 messages from 1 to 5.
Turn Airplane mode off and lock your device.
You'll only see one msg (the last one you sent aka "5") in your notifications center.
This is how whatsApp is making it work:
While whatsApp is in the background, a single push notification is received (the last one the user sent, "5" in our example). That msg will not be shown to the user.
whatsApp receives it in the method application:didReceiveRemoteNotification:fetchCompletionHandler: and checks against their servers if there are any notifications prior to "5" that the user didn't receive. If that's the case, they will pull that data from their servers and will present it to the user using local notifications which is basically just a way to present data and not related to APNS at all.
It is explained in Troubleshooting Push Notifications. Check for "Some Notifications Received, but Not All" section.
As described you cannot have any control over those push notifications.
However you may know that from iOS7 a new background execution mode (remote-notification) allows the App to be awaken by the system when a push is received, allowing you to process some data, then go back to sleep...
This is probably the trick: using that way to receive the push notifications (silently) and then trigger your own local notification instead as #Segev said. See the UIBackgroundModes here.

How don't allow iOS to start application when specific type of push notification arrives?

I want PHP server send to my iOS application two types of push notifications:
New income message. For this push I want iOS start my application if it was suspended, show badge, play sound, etc.
New friend request. I don't want this push to start my application and I only want to handle if the app is in the foreground.
How can I achieve this? How can I handle different push notifications differently?
I'm not sure if it will work, but you should try for your 2nd scenario to send a notification that contains only custom properties. In this case there will be no alert to display, sound to play nor badge to update, so I think this notification will only reach your app if it's already running.
For the 1st scenario, send a notification with pre-defined properties (alert, sound, badge).
Application-side handling for remote notifications should start with the method in the application delegate protocol application:didReceiveRemoteNotification:.
However, in order to avoid the application launching in the first place, you need to make sure the PHP server crafted notification doesn't offer the option to launch the application.
See the documentation on the Apple Push Notification Service here:
http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW9
In particular, you want to focus on the content of the aps dictionary as documented in The Notification Payload section. The aps dictionary received can badge your application's icon without opening the app at all.

Apple Push Notification Collapse Key Equivalent

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?
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.
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/).
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.
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);
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.

Resources