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

user1024447 picture user1024447 · Nov 16, 2014 · Viewed 28.5k times · Source

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?

Answer

Kevin D. picture Kevin D. · Nov 19, 2014

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