58

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?

mfaani
  • 33,269
  • 19
  • 164
  • 293
user1024447
  • 611
  • 1
  • 6
  • 5
  • Have you added the background fetch capability? – Paulw11 Nov 16 '14 at 19:58
  • Yes - fetch added in plist – user1024447 Nov 17 '14 at 08:12
  • Also, see this answer http://stackoverflow.com/questions/19068762/will-ios-launch-my-app-into-the-background-if-it-was-force-quit-by-the-user – Paulw11 Nov 17 '14 at 08:24
  • Thanks for the response but this relates to apps that are swiped - I spend some time reading all the SO posts on the subject and just to reiterate - if my app is not swiped but is running in background and is charging everything works fine and I get the silent push notifications as per docs. However, if I unplug the device from the charger I then stop getting the silent push messages. This is repeatable. – user1024447 Nov 17 '14 at 17:47
  • @user1024447 I am also facing the same behaviour.Device is receiving push notifications only when battery is plugged in.Did u got reason behind it? – user2533604 Jan 01 '15 at 07:06
  • 1
    @user1024447 Have you found any solution? I have exactly the same problem. – Santana Mar 09 '15 at 12:50

8 Answers8

66

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

Brian Sachetta
  • 3,319
  • 2
  • 34
  • 45
Kevin D.
  • 661
  • 4
  • 5
  • Kevin - thanks for you answer. Nice to know I'm not the only one. It would seem when the device is plugged in IOS always delivers the silent push messages, but when unplugged IOS is less picky about waking my app up - i.e. not only does your magic formula involve the kind of network used and the frequency of updates but also perhaps whether the device is plugged in or not... Anyway, I have noticed that the app appears to *settle down* after a few hours and I *do* now get silent push notifications when not charging *but* not as reliably as when the device is charging... – user1024447 Nov 20 '14 at 13:55
  • Yes, I think it is all battery related. If your plugged in, iOS doesn't need to worry about your App consuming too much battery power when waking you up. When unplugged, all those other factors like wifi/cellular data, time running in background, etc. affect the ammount of battery power used. – Kevin D. Nov 20 '14 at 21:55
  • The fact of my efforts: 3 different iPhones with 7.1.2, 8.1 and 8.1.2 don't process silent push until I simply plug it in USB. But my app definitely use silent pushes too much. Hope that apple doesn't take into negative account silent pushes delivered in active mode. – malex Dec 29 '14 at 14:18
  • Thanks for the posting and response. As another data point, My iPhone 5s seems to always get the silent push even when not plugged in, while the iPad Air 2 consistently gets the silent push only when plugged in. If I wait an hour or so the iPad will start receiving silent push notifications again without being plugged in. Perhaps the iPhone 5s is considered more efficient and gets more background processing time. UPDATE: The iPad finally received the silent push 15 minutes after the iPhone this time while unplugged. Hope I can convince QA this is expected behavior ;-) – Indi Jan 03 '15 at 02:16
  • Do y'all think this would also apply to non-silent notifications? For my purposes, it might be ok to do a banner instead of silent. Might that make them more reliable? – Michael Feb 17 '15 at 03:14
  • I use remote notifications to start and stop location tracking in the background, in other words heavy stuff. The notification after which locationtracking starts, is generally called within 30 minutes, but the one that is meant to stop it can take more than 12 hours. 15.5 hours in my last test: Sent at 18.13h, `didReceiveRemoteNotification:fetchCompletionHandler:` was not called until 09.41h the next day. So indeed it looks like iOS doesn't like it when you do heavy stuff based on notifications. – Arjan Mar 16 '15 at 08:42
  • @Michale. No it doesn't apply to non silent notifications. – Gruntcakes Mar 31 '15 at 21:24
  • Our experimentation shows similar results. Even though our app receives the visible push notification with content-available=1, our app never gets woken up in the background unless the phone has 5 bars signal strength or is connected to WiFi. Even then, the app does not consistently get woken up. Our background network call takes around 5 seconds, so the app might be getting aggressively throttled. Restarting the phone seems to help, but so far we have observed that our app must have WiFi or 5 bars signal strength. Disappointing. – Mike Taverne Apr 29 '15 at 19:12
  • @MikeTaverne thank you for clarification. Did you encounter any network errors inside "didReceiveRemoteNotification" while receiving silent notifications when the app is inactive ? I am receiving silent notifications but can't make a REST call after, while the app is inactive. – uahakan Jul 05 '15 at 06:38
  • anyone know if google cloud messenger on iOS behaves any differently? I'd expect not since it uses pushnotification as transport, but just thought i'd ask – Michael Sep 27 '16 at 16:13
  • I also experienced that regardless of being plugged in or not, the push notification is most of the times handled later / say 3 to 10 minutes after being sent. I suspect that the device does receive the notification, but just decides to deliver it to your app later, based on various algorithms as mentioned in other answers and comments. I intended it to use for doing something extra and notifying the user immediately, but silent notification is apparently just meant to do a little bit with your app 'somewhere in the near future, if your app behaves nicely with the power'. – morksinaanab Nov 01 '17 at 10:57
  • for messaging apps trying to appear as real-time as possible, this seemingly random throttling of the silent notifications is a significant barrier to usability with the app. This is how we manage numerous UI features. – drew.. Apr 17 '18 at 17:23
  • Thanks so much for this answer, this saved us a lot of time – Mostafa Oct 02 '20 at 11:33
9

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.

Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • not sure if what you're saying is still valid. For my Telegram App. I turned off wifi, turned on Cellular Data...had someone send me a message while my app was in background...so I received a push notification. And then turned off cellular data...opened my app. And I saw the message in my app...ie the push notification had triggered a backgroundtask... (1/2) – mfaani Jun 08 '17 at 14:31
  • Though what I also did was: I disabled wifi. Enabled Cellular. **But disabled cellular for my app**. Then I had someone send me a Telegram message. My OS still received the message/alert/notification. But when I opened my app the notification/message wasn't there. I don't think that was battery management or anything. Simply put that was the App not being smart enough to extract data from notification. (2/2) – mfaani Jun 08 '17 at 14:35
9

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

Manan Devani
  • 434
  • 3
  • 15
7

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.

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
2

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}
}
Zack Braksa
  • 1,628
  • 18
  • 26
jrlocke
  • 97
  • 5
  • 1
    If remote-notification was not enabled then NO pushes at all would be received. The question is about sometimes they are and sometimes they are not. "The silent push messages only seem to be received if the device is charging" – Gruntcakes Sep 06 '17 at 19:05
2

I hope you are using APNS delivering priority as "CONSERVE_POWER" (5), try to change it as "IMMEDIATE" (10)

aashish tamsya
  • 4,903
  • 3
  • 23
  • 34
Mohamed yaseen
  • 65
  • 1
  • 10
0

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.

Community
  • 1
  • 1
Michael
  • 2,973
  • 1
  • 27
  • 67
  • Michael, did setting the priority to 5 help you at all? – longofest Sep 26 '16 at 22:13
  • @longofest i still don't really know. it's a bit better now. one thing: MAKE SURE YOU CALL THE COMPLETION HANDLER. I am pretty sure I had several bugs where a pushnotification was not properly handled (didn't call completion handler) and so the OS thought I was taking way more time with the notifications that I am. – Michael Sep 27 '16 at 16:11
0

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

enter image description here

Husam
  • 8,149
  • 3
  • 38
  • 45
khaled
  • 865
  • 9
  • 24