My problem is: I just can't make silent notifications work when a user has force-quit(swiped away) the app!
I guess the following is a fact: A silent push (with content-available:1) will NOT trigger application(_:didReceiveRemoteNotification:fetchCompletionHandler:) nor any other method (it will NOT launch the app) if the application was force-quit (swiped away) by the user! Can anyone prove this wrong?
I have made sure I've enabled Background Mode: Remote Notifications.
But what if non-silent notifications don't work for me? I need silent ones, I need to be able to run some checks before I show it! What If I want to check if the right user is logged on to my application after I receive a notification from remote server? (since I can't guarantee that when he logged out he successfully let the server know about it, so I assume the server doesn't know for sure)
What would be the right approach to take in my situation?
There are many questions about similar things, but not many people involved, I wonder why? I don't believe that I have such a rare case. Maybe my basic approach to solving this kind of problem is wrong? It doesn't seem to be a problem on Android platform at all!
I am using FCM as central point of sending out notifications, so if you say that PushKit can solve my problems, too bad that FCM doesn't support VoIP certificates. But, I wonder, can PushKit really solve this? Or Apple just designed it this way that when a user force-quit an app, it means that this app must shut up altogether with its ability to push remote notifications?!
I don't consider this a duplicate of Firebase silent notification does not start up a closed iOS app because what I am asking here is what would be the solution if you want to check if the user to whom the notification is addressed for corresponds to the user logged in to the application? It can be considered duplicate if it turns out that there is absolutely no solution for this on iOS platform.
You ask:
Or [has] Apple just designed it this way that when a user force-quit an app, it means that this app must shut up altogether with its ability to push remote notifications?
Yes, this is how it is designed. App Programming Guide for iOS: Understanding When Your App Gets Launched into the Background says:
In most cases, the system does not relaunch apps after they are force quit by the user. One exception is location apps, which in iOS 8 and later are relaunched after being force quit by the user. In other cases, though, the user must launch the app explicitly or reboot the device before the app can be launched automatically into the background by the system. When password protection is enabled on the device, the system does not launch an app in the background before the user first unlocks the device.
Is not possible. when the app is in background or suspended modes, you will have 30 sec to do some stuff. But if user kill app manually func didReceiveRemoteNotification will never called.
Upd:
When an iOS device receives a silent notification, the system wakes your app in the background and calls the application(_:didReceiveRemoteNotification:fetchCompletionHandler:) method of its app delegate. Your app has 30 seconds of wall-clock time to perform any tasks and call the provided completion handler. For more information, see Handling Notifications and Notification-Related Actions.
Related
Is it possible to query for push authorisations by sending a silent push and have that reported back to my server?
I'm assuming silent push does not require push permissions.
Kind of, yes. If you send a silent push notification and your app has not been forced killed, then it could send back an update back to some of your servers saying that it got the notification.
Nevertheless, if the user manually quits the app, then those notifications are thrown away by the operating system, so you are not able to tell.
Also, you could simply call isRegisteredForRemoteNotifications on your application to check if the device is registered or not.
Update
To be more clearly: It doesn't matter if anything is turned on or off, you can never ever rely on the delivery of a message. The operating system may just delay the delivery, or skip it at all, and you'll never know. At least, not on the server side. Your app truely can check (once it is running again)
what kind of notifications it received (it just has to do some bookkeeping), and then ask the server if everything it has is also everything the server send sometime - but this logic has to be implemented by you.
Silent push notifications don't require push notifications permissions, but they can still be disabled by turning off "background app refresh":
Is Silent Remote Notifications possible if user has disabled push for the app?
Doing background networking requests of any kind while another app is running is a battery intensive thing to do. Many sites tell users to disable background app refresh for apps that use a lot of power. Using this feature unnecessarily could draw attention to your app and have your users disable this permission:
https://www.businessinsider.com/how-to-make-iphone-last-longer-battery-life-tip-2019-7?r=US&IR=T#:~:text=Turn%20off%20Background%20App%20Refresh.&text=That%20way%20the%20next%20time,%22%20and%20select%20%22Off.%22
You could simply check for push notification permissions on the launch of your app and record it there instead. Using silent push notifications to track the users settings is quite an odd thing to do. With everyone interested in what apps are tracking these days, and apple going out of their way to inform users of whats being tracked, doing this might get your app some bad press if it's discovered. I wouldn't install an app doing something like this, as I would be thinking "what else are they going to track while my app is off"
I am having an issue trying to have an ongoing location tracking enabled when the following conditions are in place:
Background fetch is disabled
App is killed
When the above happens, location updates are stopped. I tried to have my server send push notifications to wake the app up but they do not arrive if the app is killed.
What is puzzling is that a similar functionality seems to work just fine on WhatsApp (the live location). On WhatsApp, even if I disable background fetch and kill the app, it somehow manages to wake it up again to send updated location information.
Does anyone have any idea on what they are doing?
It seems WhatsApp could be using PushKit to get around this problem. According to this question:
WhatsApp could be using VOIP background mode along with PushKit for
solving this problem.
Voip pushes are:
delivered directly to the app.
considered high-priority notifications and are delivered without delay.
delivered even if the app was force-quit by the user.
I have also created a quick sample app to try this and it works like a charm. However, again according to the question linked, Apple doesn't really allow this solution:
Apple no longer allows the usage of the API for push notifications of non-VOIP apps. They do however allow WhatsApp to do it in their infinite fairness.
Use significant-change location services. It will work even the app is terminated.
As stated clearly in Apple docs, beacon ranging can be done in background for a short period of time only, say up to 10 seconds by default or up to 3 minutes with the help of background task expiration handler. As per my app's use case, app needs to do beacon ranging for every 15 mins until user exits the region. I am thinking of using background push notification(silent push notification) for this purpose(assuming data connection is available on the device always). So the flow goes like this, upon user entering the region, app calls the server with device token, server sends silent push notification for every 15 minutes. Once app received push notification, it does beacon ranging within allowed period of time if needed. Question I have here is whether using push notification in background mode to do ranging is legal, will I face any issues during app store submission.
Note: Also I need to enable BLE background mode for the app, to read some characteristics from some BLE devices.
Technically you can do it, but Apple mostly rejects such app. One important thing you have to consider is that, if the app is manually killed by the user and not running in the background, then the app won't wake up with silent push notification. There is a workaround if you have VoIP push notifications it will wake the app even from the terminated state. But you might need strong reason while pushing it to AppStore.
If you misuse one of the background modes, the app will probably be rejected, saying that, I don't think silent push notifications were meant for: keep an iOS app in "Background" state by sending it a silent push notification every few minutes.
another thing is that silent push notifications are rate limited as described http://asciiwwdc.com/search?q=push+notification, so I'm not sure if they will be sent every few minutes.
Apple says that;
Silent notifications are not meant as a way to keep your app awake in
the background, nor are they meant for high priority updates. APNs
treats silent notifications as low priority and may throttle their
delivery altogether if the total number becomes excessive. The actual
limits are dynamic and can change based on conditions, but try not to
send more than a few notifications per hour.
You might want to see this article. The user talks about apps that use silent notification for triggering location tracking. But eventually it's a hack that Apple may reject some time in the future, so it's best to have a contingency plan. FWIW so far I haven't heard anyone reporting rejection.
So the official answer is don't do it, as for the why you can refer to Ashish's answer. The unofficial answer is if you can't change your business logic then do it at your own risk.
The iOS application I'm working on does the exact same thing with the exception that I'm using recording instead of a Beacon. Recording by iOS standards gives more issues in pushing the app to the app store.
But Apple did not reject this app. Although we still are facing some issues but they don't relate to your problem.
You can follow such a tutorial for further help apart from the answer you were looking for : iOS Push Notification Demysitfied
Also, I've done firing of local notifications, while the application is in the background. BLE even works if the app is killed by the system, when the OS receives some communication from your peripheral or central, iOS wakes your app up and executes the desired function, before putting your app back to sleep.
We have an app that uses PushKit to receive notifications. (It is not a VoIP app but we have a dispensation from Apple to use PushKit due to being a special app category that has specific needs in healthcare).
When the app is not running and a PushKit notification comes in, the system launches the app into the background and the push kit delegate payload processor is called (PKPushRegistryDelegate pushRegistry:didReceiveIncomingPushWithPayload:forType:). Then the app is closed down again. The app never reaches a graphical interactive state.
This is fine and how it should be. However, iOS does a complete app launch, loading the storyboard and everything. In addition, in the UIApplicationDelegate application:willFinishLaunchingWithOptions:, launch options is nil, so you don't know you're being launched to handle push kit and won't be going interactive.
This is causing us problems as our app does a complete, "heavy" set up of resources, server connections, etc. that don't need and shouldn't be set up to just handle the PushKit notification. This is causing us some issues as certain things being connected (server connections etc.) cause some behavior we don't want when the PushKit is being processed (and then the app going away).
Is there a way to be able know you were launched for pushkit purposes and not do all the app setup that normally happens? (If the app were to then transition to Active we should be able to use the normal active state transition to finish setup)
Once you getting Pushkit payload in didReceiveIncomingPushWithPayload, you have to schedule local notification with info based on pushkit payload. then you can make your app interactive. you can also keep details in NSUserDefault and check on local notification tap events and in didFinishLaunchingWithOption.
This way you can initiate storyboard and get redirect to particular viewControllers.
Let me know if you need more clarification on same.
I am currently facing a problem with push notifications in iOS.
My app receives silent push notifications containing an identifier. This identifier is then used to fetch data from a remote server from which a local notification is created.
As far as I'm aware, if the user has force-quit an app (i.e. by double tapping the home button and swipe closing the app) then the silent push notification does not get passed onto the didReceiveRemoteNotification method in the AppDelegate class [1] [2], thus preventing the app from doing any kind of processing.
I have done a fair amount of research into handling the situation mentioned above. However, was unable to find a definitive answer and was hoping someone could help me out or point me in the right direction.
TLDR: What should I do when the user has force-quit my app, but I still need to process a silent notification?
Further Information:
My app only needs to support iOS8+.
[1] https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
The Notification Payload
If the target app isn’t running when the notification arrives, the alert message, sound, or badge value is played or shown. If the app is running, the system delivers the notification to the app delegate as an NSDictionary object.
[2] https://stackoverflow.com/a/19202487/2472819
Previously in iOS 7 and before, once a user force-quit an app, it will not be able to run and background tasks at all, including location monitoring, push notification handling with content-available:1 etc.
However the problem is that such behavior is not documented. The reason is that it may change in a new iOS update and Apple doesn't want to nail the coffin too early. As in iOS 8, PushKit is introduced and is supposed to be able to deal with the force-quit scenario. Please check this tutorial for details: https://zeropush.com/guide/guide-to-pushkit-and-voip