I have an app that registers itself to be woken up in the background when an APNS notification is received (i.e., the remote-notification setting for UIBackgroundModes). In the vast majority of cases this works fine. An APNS notification comes in, the app is woken up and a call to my app delegate's application:didReceiveRemoteNotification:fetchCompletionHandler: is made.
In some cases the APNS is received by the user but the app never gets woken up. It seems to only happen when the device has been inactive for a while (overnight, left behind for a weekend, etc). Once the user launches the app then everything is back to normal and subsequent APNS notifications again trigger the background wake-up.
Does anybody have an idea about what could trigger this?
Related
I just took a look at Is Silent Remote Notifications possible if user has disabled push for the app?.
It basically says the Silent Notifications disregard notification settings for user. It then says:
Users still have the ability to switch off your app’s ability to
process a “silent push” by means of the “Background App Refresh”
control. Even though Apple Push Notification service (APNs) will
deliver a push marked “content-available” to your phone, the OS will
not wake up your app to receive it, effectively dropping it on the
floor.
This is confusing to me. I want to make silent notifications go out only while the app is open, to update state of the app while in use only. So I wouldn't care if background app refresh is off because I wouldn't need to "wake up [my] app to receive it".
Secondarily Silent push notifications only delivered if device is charging and/or app is foreground talks about needing to have your phone plugged in to receive these notifications.
Both questions are from iOS 8, which is quite a ways back. Do they hold up all this time?
My answers are based on observation and my work on the apple notification.
Before iOS 13
Silent notification is not received even if notification is force killed by the user even if the background app refresh is on. Silent push received in case of foreground, background or killed by iOS
After iOS 13
Silent notification are received always if background app refresh is on.But if background app refresh is off silent push received only in foreground and background case.
If you want to only send silent push in foreground or background you should not add background mode in capability in Xcode. So it will receive only when the application is in the foreground or background
Right now I have a framework that receives a silent notification, get the data from it (custom data) and translate it into a local notification to show the alert to the user (this is donde in didReceiveRemoteNotification:fetchCompletionHandler method). I have implemented this framework on an app and everything seems to be working correctly, silent notifications are being process when the app is in background and foreground. However, when the app is killed by the user or it is not running, I cannot receive notifications because of this:
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a remote
notification arrives. However, 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.
The reason I use this method for showing notifications is because the payload I sent to APNS has custom data with key-values that indicate how the notification must behave.
I've been doing some research and I found that Pushkit for VoIP can do the job. However, many post suggest that this can cause app rejection.
So my question is, how can I achieve receiving remote notifications even if my app was killed and considering that data in the payload has custom information to build the notification?
Silent push notifications are unreliable: they might get delayed, delivered in groups or even not delivered at all.
If you need to modify the content of the notification before presenting a banner for the user, you should use a Notification Service App Extension. You can also share some information between your app and this extension - using app groups or the keychain - if it needs something from your app to process the notification data.
I am trying to implement silent push notification in my application where I need to update some data in the server when silent notification comes. I am using Pushkit and it uses VoIP certificate for silent push notification but the app has been rejectd by Apple saying that "I can't use VoIP" certificate. It seems that apple has rejected it as I don't have any VoIP call functionality in my app. In that case how can I implement silent push notification so that my app gets activated even if it is not runnning(not even in the background) and I can update the server?
From my experience, iOS respects user's choice, so in case the user has killed the app, it will remain killed - no silent push notification will wake this app. VoIP is an exception to that, but as you wrote, it should be used only in VoIP apps. This makes sense, consider it a platform limitation: thanks to that user have some control over what is actually running on the phone, the device consumes less battery and lastly, foreground/system Apps has the most CPU time to utilize.
There are few techniques to work with data in the background:
Content-available push notification: will wake up the application in case it is suspended, or startup it in case it has been killed by the system/crashed. Note, that this only opens a 30-second window and amount of notifications is throttled by APNS.
Background fetch capability will act in a similar manner.
Background task to finish existing task - but this is only used when app is moved to the background.
If you need App to send updates to the server, I believe above should be sufficient (unless your app is spying on a user, it should have all relevant data available once the user finishes interaction with the App).
If you need a server to send data to the App, use silent push notification (or background fetch for periodic pulling), or in case this data is critical to the user, you can present him a remote notification - if the user considers that an important update, he will open the app.
According to Apple's documentation on remote notifications:
Discussion
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which
is called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a remote
notification arrives. However, 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.
In my case (iOS 7.1.1) remote notification is not delivered to the app after the app was killed (swipe up from Recent Apps List) and the phone was restarted. If I open the app, notifications get delivered as expected. What am I missing?
Edit: To avoid any misunderstanding. What I expect is the following flow:
User kills the app;
User restarts the phone;
App server sends a new message;
OS attempts to launch the app and deliver the notification.
The problem is that you are a developer, and your usage is not typical. What you do: Launch the app, swipe it out, turn off the phone (not standby, but turned off), reboot, enter your passcode, make your server send a notification. That doesn't work.
For some reason, notifications sent within 90 seconds or so after rebooting the phone are not received. Wait 90 seconds, then you send the notification, and it should be received. Since there is no relation between the time the phone of the user is rebooted and the time you send the notification, this is only a problem for developers and testers, not for real users.
From the article you linked, for the method you're referencing (application:didReceiveRemoteNotification:)
If the app is not running when a remote notification arrives, the
method launches the app and provides the appropriate information in
the launch options dictionary. The app does not call this method to
handle that remote notification. Instead, your implementation of the
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method needs to get the
remote notification payload data and respond appropriately.
Are you checking for your remote notification payload in the options dictionary for the will/didFinishLaunchingWithOptions:?
It looks like no matter I return UIBackgroundFetchResultNewData or UIBackgroundFetchResultNoData from performFetchWithCompletionHandler, it clears all previous notifications (local or push) for my app. This is not acceptable for me.
Anyone knows how do I do fetch and not make previous notifications cleared (disappear)?
My guess here is that you had a background fetch that was setting your badge number to 0, if that ever happens all your notifications are cleared.
Source: Apple's AppDelegate API Reference
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
Tells the app that a remote notification arrived that indicates there is data to be fetched. Use this method to process incoming remote notifications for your app. Unlike the
application(_:didReceiveRemoteNotification:)
method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, 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.
If the user opens your app from the system-displayed alert, the system may call this method again when your app is about to enter the foreground so that you can update your user interface and display information pertaining to the notification.
Note: You need to make sure that the app is checking for the state before settings the application's badge number to 0. Test the below cases:
Application running, receives a notification
Application terminated, receives a notification
Launch app directly from app icon
Launch app from notification received
Knowing the difference between the 3 approached below is essential in your use case.
Checking the notification object received in application(_:didReceiveRemoteNotification:)
Checking the notification object received in application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
Checking the didFinishLaunchingWithOptions for UIApplicationLaunchOptionsRemoteNotificationKey