Delegate method of push notification is not hitting after few hours - ios

I am sending silent push notification for my ipad for every hour. But after few hours the delegate method is not hitting(I have put a local notification inside delegate method).I am using this
application:handleActionWithIdentifier:forLocalNotification:completionHandler: delegate method to handle silent push notification. When i reset ipad under settings and try to send push notification, the delegate method will hit and work as i expected. I am not understanding this behaviour. I have also put sound to my notification,which plays when notification reaches device.But delegate inside my app is not hitting.My delegate code is as below.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
//some database operations
completionHandler(UIBackgroundFetchResultNewData);
}

1.APNS is based on Apple Servers, and Apple doesn't give any guarantee on successful message delivery.
2.If the app is open (i.e. the user is using the app) while the notification arrives, iOS doesnt show a notification message, you need to handle it.
3.Notification shows up only when the app is backgrounded or killed.
4.Also implement feedback service on your server side; will help you get rid of old unwanted tokens(users who deleted the app or disabled notifications thru settings).
5..Dont send too many notifications to a device within a short span of time, coz APNS caches only 1 message/device (if the device is offline). So it can deliver the message when the device comes online. Am not sure how long the message is cached though.
Some Notifications Received, but Not All
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.
Here's why. The device or computer acknowledges receipt of each notification. Until the push service receives that acknowledgment, it can only assume that the device or computer has gone off-line for some reason and stores the notification in the quality of service (QoS) queue for future redelivery. The round-trip network latency here is of course a major factor.
As described in the Local and Push Notification Programming Guide, the QoS queue holds a single notification per app per device or computer. If the service receives another notification before the one in the queue is sent, the new notification overwrites the previous one.
All of this points out that the intent is that a notification indicates to an app that something of interest has changed on the provider, and the app should check in with the provider to get the details. Notifications should not contain data which isn't also available elsewhere, and they should also not be stateful.
Any push notification that isn't delivered immediately was queued for future redelivery because your device was not connected to the service. "Immediately" of course needs to take latency for your connection into account. Outlying cases would be beyond 60 seconds as APNs will time out at that point.
APNS Technical Note TN2265

Related

How does WhatsApp bypass APNS restriction to display multiple push messages received while device was offline?

While working with APNS, I was able to have push notifications work flawlessly while device is online.
For any APNS push I send while device is offline, only the last one is received once the device is back online. This seems to be coherent with Apple's Store-and-Forward design.
However - I did notice, that when sending WhatsApp messages to an offline device, once this device goes online it receives all push notifications (one for each message). This is not something based on collapse identifier, but rather independent push notification for each message.
So how did WhatsApp do it?
Tried using Notification Extension and attempt to post multiple local notifications, but this also fails as extensions are not allowed to do that.
Instead of a normal push notification, use a Background Notification, which will not show anything visible, but wake up your app in background. Use this event, to make api call, get relevant data and generate multiple local notifications.
Note the following from the documentation when you implement application(_:didReceiveRemoteNotification:fetchCompletionHandler:) :
system calls this method when your app is running in the foreground or background
system does not automatically launch your app if the user has force-quit it
you must call the block in the handler parameter (fetchCompletionHandler) or your app will be terminated. Your app
has up to 30 seconds of wall-clock time to process the notification
and call the specified completion handler block
Apps that use significant amounts of power when processing remote notifications may not always be woken up early to process future
notifications
Please read relevant documentation completely before making ANY assumptions about how you think this should work.

End-to-end tracking of ios push notification [duplicate]

I build xcode app that get push notification, the main problem is that the push notification is very critical for me.
so I want to check if the push notification is delivered to the device with the app installed, I understand that if the iphone dosn't have internet connecction / 3G the push notification is not getting to the device.
how can I check if the device get the notification or not?
how can I check if the APNS successful to deliver the push notification?
I want to send sms if the push notification is not deliver to the device so I think about the idea to get the notification event when it's open by the push notification, and to send request to my server so i can know if the push notification is successful deliver or not. the main problem is that the user need to open the app every time he get the notification and in the night it's a problem. so this option is not good for me.
I check the feedback server push notification but i don't find any info that I can get if the push notification is delivered or not
any idea??
With iOS7 you have a new method called
application:didReceiveRemoteNotification:fetchCompletionHandler:
which you probably could use for your task. From Apple's Docs:
Implement this method if your app supports the remote-notification background mode.
...
When a push notification arrives, the system displays the notification to the user and
launches the app in the background (if needed) so that it can call this method. Use this
method to download any data related to the push notification. When your method is done,
call the block in the handler parameter.
Unlike the application:didReceiveRemoteNotification: method, which is called only when
your app is running, the system calls this method regardless of the state of your app.
The short answer, you can't, since APNS is one way. However, since an app can execute arbitrary code upon receipt of a notification, you can use this to say, send an http request to your own server when the notification is recieved.
There are any number of reason why push notifications might not get delivered to your user, or might not be delivered in a timely manner. Apple does not provide any mechanism for you to query the status of a push notification that you have sent.
If your app is currently running on the user's device and the user is accepting notifications for your app, you can implement the following method in your app delegate. It would be called whenever a push notification is received and in this method you could send a request back to your server to indicate the message was received. However this will only work while the user is running your app.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
In general though, it sounds like you'e relying on push notifications for something you shouldn't. From Apple's Local and Push Notification Programming Guide:
Important Because delivery is not guaranteed, you should not depend on
the remote-notifications facility for delivering critical data to an
application via the payload. And never include sensitive data in the
payload. You should use it only to notify the user that new data is
available.
There is no way to find out whether the notification was delivered to the device or no. APNS is a one way service. If there is no internet connection on the device then the APNS server will hold the last notification for some period of time which is no specified by Apple. If a new notification is sent to APNS for delivery then the old notification data is lost and replaced by the new data if its undelivered. If the notification is delivered then also the old notification data is deleted on the APNS server.
Please go through the following link : Apple Push Notification
Hope this helps you...........
If you are using JAVAPNS to send the APNS notification, you can use the below:
List<PushedNotification> notifications =
Push.combined("alert", badge, "default", "cert.p12", "certpassword", true, deviceToken);
for (PushedNotification notification : notifications) {
if (notification.isSuccessful()) {
//Push is successful. Do your thing...
}
else {
//Push is not successful. Do your thing...
}
}

Is there any mechanism to know the delivery status of Remote Notification

I trying silent push notification to wake app in background and calling a specific Api but it doesn't work properly
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{//Fetching data using AfNetworking
completionHandler(UIBackgroundFetchResultNewData);}
By the way : whatsApp doing something like this:
notify the sending user that the message is delivered to receiving user
Silent notifications will NOT arrive when:
- background fetching is disabled
- the user has killed the app by sliding up from the app chooser screen
WhatsApp most likely sends notifications that has an 'aps' payload (which will cause iOS to display it on the notification screen), and the 'content-available' flag present (which will cause iOS the forward it immediately to you app, if not prevented by the 2 conditions above).
Once the app is opened by the user, the app will let the server know which messages have been displayed on screen. The server could then send a silent push, or have the app poll while active, to update the checkmarks on screen.
The thing to remember is that push notifications are not reliable sources o truth. They are 'pinging' the app, and the app and server need to implemented the actual logic.
Push notifications are fire-and-forget by design, and they're not even guaranteed to be delivered to client device. So no, you cannot confirm delivery of a push message.
WhatsApp and other messengers must be using their own infrastructure to track messages' delivery.
I found Working around on this Problem and Answer it at this question
Silent push notifications only delivered if device is charging and/or app is foreground

Silent push notifications only delivered if device is charging and/or app is foreground

I have implemented silent push notifications but I have noticed some strange behaviour. The silent push notifications are handled via:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
The silent push messages only seem to be received if the device is charging (ie cable connected) and/or if my app is foreground.
If I disconnect the device from the charger (or Mac) then the silent push notifications are no longer received unless the app is foreground.
I get non-silent push notifications normally in both cases.
If I plug in the USB cable again, then I get the expected behaviour and silent push notifications are received irrespective of whether the app is foreground or background.
I am using UILocalNotification so I know what is being received.
The fact that it all works fine with the device connected suggests that my silent pushes notifications are configured correctly and that the app has the correct background modes set in the plist etc.
This behaviour is repeatable on iPhone 5s, 6 and iPad 2 all running either IOS 8 or 8.1.
Has anyone else experienced this? It should be easy to reproduce. Why should the simple act of plugging a device into a charger change the ability to receive silent push notifications?
We have experienced the same behavior and have been trying to understand why iOS decides to deliver some notifications and not others.
What we have worked out so far is:
Messages will get received more reliably in background when on wifi than on cellular data. In fact, when on a cellular network (3g/4g), if your signal strength isn't strong enough, iOS receives the push message, but will not wake up your app. We posted in the apple forums about it here: https://devforums.apple.com/message/1069814#1069814. We also opened up a support ticket, and the support team told us to lodge it as a bug report, which we did a couple of weeks ago and are still waiting to hear back.
When you receive a push message, you need to call the fetchCompletionHandler as soon as possible. Technically you have 30 seconds to perform background processing, but iOS has in place a formula whereby the more frequently you send push messages and depending on the amount of time you spend processing those message before returning the app to suspended state, iOS can reduce the amount of times your app gets woken up in the future.
See here from Apple didReceiveRemoteNotification:fetchCompletionHandler: documentation:
As soon as you finish processing the notification, you must call the
block in the handler parameter or your app will be terminated. Your
app has up to 30 seconds of wall-clock time to process the
notification and call the specified completion handler block. In
practice, you should call the handler block as soon as you are done
processing the notification. The system tracks the elapsed time, power
usage, and data costs for your app’s background downloads. Apps that
use significant amounts of power when processing push notifications
may not always be woken up early to process future notifications.
In our testing, we have been sending frequent silent push notifications to our app (every 10 - 30 seconds). And the app is awake for about 3 seconds before we put it back to sleep. We have definitely noticed over time a degradation in the frequency in which our app gets woken up to the point where iOS will only wake up the app every 15 - 30 minutes. So there seems to be some sort of decay/throttling formula in place, but we cannot find any documentation on how it exactly works. We have requested this formula and the variables from apple as a support request, but they said "The information you are requesting is not publicly available" and again asked us to file a bug report.
So, hopefully this is helpful? We are still trying to learn more ourselves which is why I found this question :)
With iOS8 background push delivery to apps has changed. A background push will now only be delivered to the app under certain circumstances. Apple have not stated explicitly what these circumstances exactly are but from my extensive experimentation it basically comes down to if the phone is being charged or not. There are some other variables at play (such as network type, device type, wifi enabled) but the major major major factor is whether the device is being charged or not when the push arrives.
If the phone is being charged via a direct mains power supply or indirectly by being connected by USB to a computer then the background pushes will get delivered to the app the vast majority of the time. But disconnect the phone from the power supply or USB and the background push will almost never get delivered to the app, even if the phone's batter has a 100% charge.
You can very easily test this for yourself just by sending some pushes while the phone is being charged versus while its not. BUT you must take into account that background pushes with a development build and using the sandbox environment DO NOT behave the same as background pushes with a production build and a production environment, the background pushes are actually more likely to be delivered to the app in development then they are in production so it is vital you test using a production build and Apple's production environment to see the actual results.
Note there are two steps the push delivery, the first is it needs to get delivered to the phone itself, the second is once the phone has it, it then needs to get delivered by the OS to the app. In iOS7 things such as turing on Wifi made the chances of the push getting to the phone increase. With iOS8 however even though the push is successfully being delivered to the phone, the OS is not forwarding it on to a background app if the phone isn't being charged. This means the phone gets the notification and holds on to it, sometimes for several hours, before it might forward it to the app if the phone isn't being charged.
I had experienced the same problem and the reason behind not receiving push notification while the app is not charging is that when the Low Power Mode is enabled from Settings > Battery it disables background-fetch feature for all applications.
Which prevents device from receiving push notification.
This link might be useful.
Apple Documentation
I also noticed the same and wasted some time figuring out. See https://stackoverflow.com/a/31237889/1724763
If you turned off Bg App Refresh, silent remote push will be dropped silently (the irony).
However, my observation is that if you connect to Xcode via cable, somehow the Bg App Refresh setting is ignored and all silent push for your app works.
I highly suspect this is an undocumented feature: charging causes the Bg App Refresh setting to be ignored.
It's not working because you have enabled the wrong background mode in the plist. You need to enable the remote-notification tag (App downloads content in response to push notifications), not fetch. Fetch is used for something else. You may also need to use the content available key in your JSON payload, e.g.,
{
"aps": {
"content-available": 1
},
"yourdatakey":{data}
}
I hope you are using APNS delivering priority as "CONSERVE_POWER" (5), try to change it as "IMMEDIATE" (10)
I've been experiencing this problem for some time, and am very grateful for this question and #Kevin D. sharing their understanding. I'm beginning to think that https://stackoverflow.com/a/30834566/1449799 and https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW4 (see priority in one of the tables) are describing why my app is having trouble:
It is an error to use this priority for a push that contains only the content-available key.
To send the notifications, I'm using node-apn where the default (which i also need) is to set the priority to max (10 [beware, it looks like only 10 and 5 are correct values at this time]), but since i wanted a silent notification, i don't have alert, badge, or sound set.
IF YOUR APP IS NOT VoIP YOU CAN'T FOLLOW THIS ANSWER [your app will be rejected]
I found another solution that is worked for me using PushKit Framework
VoIP pushes provide additional functionality on top of the standard push that is needed to VoIP apps to perform on-demand processing of the push before displaying a notification to the user
When I send VOIP Push the App wakes up whatever the state of the Application and can perform any operations
Register for VOIP PushNotification in didFinishLaunchingWithOptions
PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
NSLog(#"voip token NULL");
return;
}
NSString *originalToken=[NSString stringWithFormat:#"%#",credentials.token];
NSString *token = [originalToken stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"PushCredentials: %#",token);}
then you can handle any background fetch in this function once you receive VOIP PushNotification
-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
NOTE: you must use certificate that enable VoIP Services Certificate

didReceiveRemoteNotification is not called for every push notification

It seems that if I send multiple push notifications to the same device, at the same time, didReceiveRemoteNotification is not called for every notification sent. Lets say I send 6 notifications, didReceiveRemoteNotification is only called on average 3 times. That's if the app is currently running. BUT if I am outside the app and send 6 push notifications, all will be delivered to the notification center/lock screen. Is this the expected behavior?
That's the expected behavior:
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.
While in your case the device in online, the important thing to note is that only one notification is stored for your app for each device by APNs. Suppose you send 3 notifications at once. The APN server is delivering the first message to the device when the second message arrives. It stores the second message. Then the third message arrives while the first is still being delivered, so the third message overrides the second, and the second is never delivered.
Here another quote which you may find more convincing:
Some Notifications Received, but Not All
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.
Here's why. The device or computer acknowledges receipt of each
notification. Until the push service receives that acknowledgment, it
can only assume that the device or computer has gone off-line for some
reason and stores the notification in the quality of service (QoS)
queue for future redelivery. The round-trip network latency here is of
course a major factor.
As described in the Local and Push Notification Programming Guide, the
QoS queue holds a single notification per app per device or computer.
If the service receives another notification before the one in the
queue is sent, the new notification overwrites the previous one.
All of this points out that the intent is that a notification
indicates to an app that something of interest has changed on the
provider, and the app should check in with the provider to get the
details. Notifications should not contain data which isn't also
available elsewhere, and they should also not be stateful.
Any push notification that isn't delivered immediately was queued for
future redelivery because your device was not connected to the
service. "Immediately" of course needs to take latency for your
connection into account. Outlying cases would be beyond 60 seconds as
APNs will time out at that point.
Source

Resources