Preserving read push notifications - ios

I was wondering if it's possible to keep the last 5 (for example) read notifications in the apple's notification center (the one that shows up when you swipe down near the top)
I've noticed that once you click on a notification and "read" it, it disappears from the list. Is this done programaticaly by the app, who sends the device a message that the notification has been read and it's ok to delete it, or is it done automatically by the device and you have absolutely no control on it.
One client said it saw an app that did this and kept the last 5 notifications there, regardless if they were accessed or not but so far I've found nothing to indicate that this is possible

Well, it's not a very complete answer, but one of my colleagues managed to make this work.
All he did was to stop using badge number for notifications. No badge number is set when a notification is received, and no badge number is set when a notification is read.
[edit]It seems that when you set the badge number to 0 after you receive the notification, iOS automatically clears the notification, this being an undocumented feature.

You can only "read" the notifications sent to your App, and only if the user explicitly used their "action" button to open your App. if that was the scenario you can use:
// Handle local notification if received
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] != nil) {
NSLog(#"received a local notification = %#", [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]);
// Do something, save it..
}
// Handle remote notification if received
if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey] != nil) {
NSlog(#"received a remote notification = %#", [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]);
// Do something, save it..
}
Or other alternatives (NotificationCenter etc) to read the notification when the app is opened with it and save it persistently.

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])

iOS doesn't receive Push notification when the app is being killed

I have found similar questions on Stack Overflow, but none of them have cleared the point.
I am using Firebase Cloud Messaging for sending push notifications in my app. I am storing the messages received in a local database. When my app is active or in the background, my app is able to receive the notifications (delegate methods called properly) but if the app is being forced quit or not in the memory then also the device is receiving the notifications and sat in notification center but the none of the delegate methods called when the app is being launched by an icon. If a user clicks on Message in the notification center, then the app gets launched, but only the message clicked on is being received and not all of them (in the case of multiple notices have been received).
According to Apple - The system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
But even if the user launched the app still not receive the notifications which were received and sat in the notification center.
Here are the points followed by the app:
My app has no VoIP functionality.
Content-available has been set to 1.
Has enabled to receive background remote notifications.
All notifications sent has been received and displayed in the notification center.
{
aps = {
alert = {
body = "Push Notification Test Message";
title = Push Notification;
};
badge = 1;
"content-available" = 1;
sound = default;
};
"gcm.message_id" = "0:1499340350307980%361a2e5b361a2e5b";
m = "Push Notification Test Message";
tag = m;
}
If the app is being forced quit or not in memory then your app will not receive silent notifications(i.e. Content-available set to 1).
Only push notifications are received in above conditions.
If user clicks on Message in notification center, then app gets launched and only that clicked the message will be received in delegate methods.You cannot access all the messages in the notification tray.
There is no way to get push notifications for the application if app is not running. This is restriction . You are only can get and clear local notifications. So the another way of resolving your problem is saving your notification on the backend when you send it. Then after launching app , you can get notifications list from the server , and match it with id . You can send any parameters that you want in notification playload.
Your app should not rely on the delivery of push notifications. Delivery of push notifications is not guaranteed, as you have found.
Even if your app isn't terminated you may not receive all notifications; For example if the device is in airplane mode and multiple notifications are sent, only the last one is delivered when the device comes back online.
Your app should check with the server for new messages when it is launched or when a notification is received in order to "catch up".
You can also consider including a message payload in your silent notifications. This will be displayed to the user if your app is terminated to prompt them to open your app.
You need to handle method for push notification when the application is open from a tap on any notification. As soon as you tap on notification application will awake and lunch it.
In didFinishLaunchingWithOptions, you need to put below condition:
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:[launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey]];
}
It also called below method when notification is tapped:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
{
}

Handling push notifications iOS when app is force-quit by user (Alternatives?)

I have a problem with push notifications in iOS, in a similar scenary to this and this and another one.
Also, this post resume all possible situations.
In my case:
app is NOT RUNNING
content-available:1
UIBackgroundModes contains 'remote-notifications' and 'fetch'
If the user force-quit the app and receives a push notification, then it could open app from alert or from icon.
When the user tap on the notification the app will be opened and the following method will be executed:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Handle for notifications when app is closed
if (launchOptions) {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if (apsInfo) {
// handle notification
}
}
No problem up to here, I have the payload to doing something with that info (for example to fetch new data from server).
But if the user open the app from the icon I don't have any way to handle the payload (Although didFinishLaunchingWithOptions is execute, I don't have the aps info, according to docs here).
So, the question is, there are any way to solve that?
For example, I made the test with WhatsApp, and they handle that situation, (probably they are using VOIP notifications instead of Remote Notifications)
Regards
You should never assume that state has remained consistent between the time the notification has been delivered and the time the user has launched the app. Nor, even, that it is the same device. I'll frequently get a "Hey! Do something!" notification on my phone and, if my iPad is handy, respond to it on my nice big iPad screen.
Instead, you should round trip to the server and grab the most up to date state for that user at the time of app launch or activation.

How to get an array of all pending remote notification?

Scenario:
My application is closed (not in background).
I received more than 1 remote notification.
I click on app icon (not on remote notifications).
How can I get array of JSON payload for received remote notification (more than 1).
Thanks in advance.
Unfortunately this is not possible.
You will only receive information about the notification that was used to open your app. If a user opens your app, and you have more than one notification, you will not be able to retrieve all of them from in the app.
Only one recent notification for a particular application is stored. If multiple notifications are sent while the device is offline, each new notification causes the prior notification to be discarded.
Apple Push Notification Service
APNs
Quality of Service
Apple Push Notification service includes a default Quality of Service (QoS) component that performs a store-and-forward function.
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 application 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.
If the device remains offline for a long time, any notifications that were being stored for it are discarded.
Source
iOS
You can get a hold on only the last remote notification.
As iOS 10 it is possible
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
NSLog(#"msg getDeliveredNotificationsWithCompletionHandler count %lu", [notifications count]);
}];
You can do it like this
func getAllDeleveredPendingNotifications() {
let center = UNUserNotificationCenter.current()
center.getDeliveredNotifications { (notifications) in
print("pending notifications \(notifications)")
for info in notifications {
let userInfo = info.request.content.userInfo
print("UserInfo is \(userInfo)")
}
self.removeAllPendingNotification()
}
}

Silently send push notifications from my server to my app

Setup: I have successfully deployed a push notification system on my server! That being said, I am able to send notifications to my iOS devices which can send alert messages when something happens on the webserver, for example: when a new customer is added to the system.
This displays a nice message like so
You have a new customer. More money baby!
And the notification is of course silent when my application is open but simply automatically updates the customers table for me so I don't have to manually keep refreshing my table.
Problem: Since then the system has scaled up and now I'm getting messages like that to my device all the time at least a few every hour, this bothers me.
My proposed solution is to only update my table every single time a new user is added so this would require a push notification to be sent for every new user that is created, thats perfect, but for it to not display messages on my notification center like it did before.
Question: Is there a way to silently send push notification so that I don't get any messages like that on my device, but when the application is running for the push notification to still pop through so that I can update the UI without having to manually refresh my customer's table?
Is it just a case of leaving blank body parameter of the json push notification sent from my server?
What I don't want: I don't want to resolve to having to hide the notification from my own application :')
You could use the silent push notifications of iOS 7+.
If into the payload that you send from your server you add the key "content-available" with value 1 and remove the key "alert", you will get the push but with out get the message on your screen.
When you receive this kind of push you will have 30 seconds of execution time*, time that could be enough to refresh your user table and next time you open the app you will have up to date the table data.
The system will wake up your app and call the method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
on the AppDelegate.m
The format payload should be that:
{"aps":{"content-available":1}}
also you could add more fields if you want like badge or extra dictionary data to use it, are optionals.
{"aps":{"content-available":1, "sound":"", "badge":1}}
If for some reason you are not getting the push try adding "sound": "", seems like could be a bug around the silent push.
*Don't forget that execution time due to silent push won't happen if the you or the use swipe up the app and terminate it.
I hope this is useful for you! :)
According to the "Local and Push Notification Programming Guide", the aps dictionary contains one or more properties that specify the following actions:
An alert message to display to the user
A number to badge the application icon with
A sound to play
So you could send a notification that contains a badge count only. The payload would
look just like
{
"aps" : {
"badge" : 9
}
}
here it the format
/*
aps =
{
Name = "";
alert = "Testing";
price = 0;
//sound = default;//do not send it from server
type = add;
};
*/
in swift get remote notification when app is open
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
{
if let aps = userInfo["aps"] as? NSDictionary {
var message = aps["alert"]
println("my messages : \(message)")
}
}

Resources