I'm working on getting background notifications to work on IOS with GCM - non-background notifications are already working.
In background notifications sometimes come and sometimes not.
I used conten_available = 1;
I successfully obtained a Registration Token and subscribe to topic:
Registration Token:
nU8ef5ZzonI:APA91bFaazXpqgI2wKTCujMaLLIZaKOmdpPAz2_WRc3V54d4eEI8p8VeAUZLwMAQ_8iaDDQ4XJAS44dFyIQkXcZ8cJjVdEGUEgnNOtrqxBKFHDTtPOUf2xT28vRprdStdVNzvrBFCQ3
Connected to GCM Sep 2 17:37:24 iPhones-iPad News[4201] : Already subscribed to /topics/news
But often in the backgrounds the application does not receive notification.
Or, the notification may come all at once old and new.
Why notification work so unstable?
You said "But often in the backgrounds the application does not receive notification. Or, the notification may come all at once old and new.".
Meaning not that they don't come, but they are delayed. Background pushes often are not immediate delivery and may take several hours.
If the user force quits the app they will not be delivered at all.
If you plug your iPhone into a power charger (or connect it to a computer via a charging usb cable) and try again you will most likely find they are delivered immediately. This is because starting with iOS8 background notification delivery is tied to power saving and hence why you will see them delayed and bunched together when they are delivered.
Related
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.
I have a messaging service that I use for regular push notifications. For example, when one user sends a message, the other user receives a push notification with that message. I have noticed if the phone is on wifi and 3g / 4g, and the app is killed (and the screen is locked), the notification will be received. If the device is only on wifi and the app is killed (and the screen is locked), the notification is not received.
My assumption is that in order to conserve battery, the device disconnects from wifi after a certain time, and that is why push notifications are not received.
But when I use VOIP push notifications, the situation is different. Even if the app is killed and the device is on wifi (and the screen is locked), the notification will be received. So what does this mean? How is phone receiving this notification, if it disconnects from wifi?
What am I missing here?
Furthermore, to add to Sivajee Battina's answer, this is what you can read in the guidelines:
There are many advantages to using PushKit to receive VoIP pushes:
The device is woken only when VoIP pushes occur, saving energy.
Unlike standard push notifications, which the user must respond to before
your app can perform an action, VoIP pushes go straight to your app
for processing.
VoIP pushes are considered high-priority notifications
and are delivered without delay.
VoIP pushes can include more data than what is provided with standard push notifications.
Your app is automatically relaunched if it’s not running when a VoIP push is received.
Your app is given runtime to process a push, even if your
app is operating in the background.
So the third point confirms that your standard push notifications can be delayed in certain circumstances, while VoIP push notifications will always be delivered instantly.
Also, have a look at this question for reasons why standard push notifications are delayed or dropped.
You are almost correct in this - this is how voIP works. Excerpted from Apple Docs:
In the past, a VoIP app had to maintain a persistent network
connection with a server to receive incoming calls and other data.
This meant writing complex code that sent periodic messages back and
forth between the app and the server to keep a connection alive, even
when the app wasn’t in use. This technique resulted in frequent device
wakes that wasted energy. It also meant that if a user quit the VoIP
app, calls from the server could no longer be received.
Instead of persistent connections, developers should use the PushKit
framework—APIs that allows an app to receive pushes (notifications
when data is available) from a remote server. Whenever a push is
received, the app is called to action. For example, a VoIP app could
display an alert when a call is received, and provide an option to
accept or reject the call. It could even begin taking precursory steps
to initiate the call, in the event the user decides to accept.
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
I'm testing Apple push notifications for our iPhone app. The app deployment target is 6.1 and the iPhone is running 7.1.1. We use Apigee as our push notification provider. The phone receives notifications when it's online via cellular and wi-fi, confirming that registration is correct on the app side and Apigee side. I turn on Airplane mode, push a notification from Apigee, wait 3 minutes, take the phone out of Airplane mode, and the phone never receives the push notification. I wait a few minutes (up to 30), then push another notification from Apigee and the phone receives the notification.
I've read Apple's Local and Push Notification Programming Guide and I've read Technical Note TN2265 Troubleshooting Push Notifications.
According to the troubleshooting guide, "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." This is why I wait 3 minutes. I also know that APNS queues a single message and I think I know that I'm not overwriting that message - unless latency/throughput with the APNS QoS queue is much worse than a few minutes.
In Apigee, in Message History, I see the notification that was sent when the phone was offline. It has a status of Finished with total sent: 1, total errors: 0. I also see a receipt under Data/receipts. This seems to indicate Apigee successfully sent the notification to APNS (but I'm not 100% sure). I verified that the notifierId from Apigee is the same for all notifications sent when online and offline.
Is there any technique I can use to see why the notification is not being delivered from APNS? Is there anything else I can check?
You are correct, if the Notification is showing no errors and a Receipt has been created, the message was properly delivered to APNS.
The only thing I can think of outside of any vagaries of APNS itself that can affect your delivery is if you set the "expire" property on your Notification. Have you tried to see if that makes any difference to your result?
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