I am working on an iOS app for which I need to show a local notification when users force quit the application.
I tried to use the "applicationWillTerminate" iOS callback but it doesn't work when the app is killed from the multi-tasking window.
From the official Apple documentation, it appears that there is no way to detect the force quit app event (from the multi-tasking window) but I found that Alarmy app can show a notification when we force quit the application.
Questions:
How this "Alarmy" app can show the force-quit app notification? What possible approach is used by the application?
Are there any workaround solutions for this problem?
I would appreciate any suggestions and thoughts on this topic. Thank you.
When app terminates, the following delegate will be called:
- (void)applicationWillTerminate:(UIApplication *)app
{
}
To receiving the terminate event, you need to add the UIApplicationExitsOnSuspend key to your info.plist.
I'm working on an iOS application which had Background Fetch enabled via the Info.plist for around a year. There were multiple versions released with background fetch enabled, but then a few weeks ago the feature that necessitated background fetch was removed. The UIBackgroundModes key was removed completely from the Info.plist, and the app was released to the App Store.
Surprisingly though, telemetry indicated that the application was still being launched in the background periodically! This is a snippet from the actual app delegate source code:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// NB: this callback should NEVER happen! But if it happens, we want to know about it.
... send telemetry log here ...
completionHandler(UIBackgroundFetchResultNoData);
}
Has anybody experienced anything similar? According to the documentation, it should be impossible for the app to be launched if the UIBackgroundModes dictionary don't contain the right values. In this case, there's no background mode turned on at all, yet the app is periodically launched in the background to perform the fetch...
Telemetry data indicates that it happens on iOS 11 only, but that might be a coincidence because only a small fraction of the installed base is on iOS 9/10.
BTW a source level assistance request was sent to Apple with this issue, but they haven't replied yet; but maybe developers of other apps have encountered this issue before.
I've written a simple application in order to test and monitor how the background fetch feature works in iOS7.
First of all, I've set UIBackgroundMode options in my Info.plist file.
Then;
I added to below code into application:didFinishLaunchingWithOptions: method in AppDelegate.m:
At last, I've implemented the application:(UIApplication *)application
performFetchWithCompletionHandler: method as requested.
Every time I click Debug->Simulate Background Fetch button, it changes the application's batch number and works as expected.
However, I've never been able to make it work when the application is not running (not even in the background mode, just not running).
Apple says that when the application is not running and OS wants to execute the following methods respectively:
application:(UIApplication *)application didFinishLaunchingWithOptions:
applicationDidEnterBackground:(UIApplication *)application
application:(UIApplication *)application performFetchWithCompletionHandler:
So my question is that is there a way to test background fetch when the app is not running?
I am testing this on my iPod 5th Gen with iOS 7.1.
Edit 2: Note that if a user kills the app from the app switcher, the background fetch will never happen again. This is working as Apple intended. See the related "Understanding When Your App Gets Launched into the Background" docs for details:
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.
And an old developer forums post (the link unfortunately no longer exists)...
"If you kill an app from the multitasking UI, the system will never
automatically launch the app again. The logic here is that, if the
user has killed your app, they probably want it to stay dead."
You could make a simple GET request, eg: "http://dev.example.org/?ping=1" to your web server then grep the access.log on the web server for "?ping=1"
Edit: Another method to test the app being launched in the background (eg: without being able to double tap the home button and switch to it) is by creating a background-only scheme. Go to Product -> Scheme -> Manage Schemes and then duplicate your default scheme.
Then edit the new scheme and click the Options tab and check "Launch due to a background fetch event" - when you run your app it'll be launched directly into the background, as it would through normal use.
I am triggering a background fetch by using the content-available flag on a push notification. I have the fetch and remote-notification UIBackgroundModes enabled.
Here is the implementation I am using in my AppDelegate.m:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Remote Notification Recieved");
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Looks like i got a notification - fetch thingy";
[application presentLocalNotificationNow:notification];
completionHandler(UIBackgroundFetchResultNewData);
}
When the app is running in the background, it works fine. (The notification is received and the app triggered the "looks like i got a notification" local notification, as the code above should do).
However, when the app is not running and a push notification is received with the content-available flag, the app is not launched and the didRecieveRemoteNotification delegate method is never called.
The WWDC Video Whats New With Multitasking (#204 from WWDC 2013) shows this:
It says that the application is "launched into background" when a push notification is received with the content-available flag.
Why is my app not launching into the background?
So the real question is:
Will iOS perform background tasks after the user has force-quit the app?
UPDATE2:
You can achieve this using the new PushKit framework, introduced in iOS 8. Though PushKit is used for VoIP. So your usage should be for VoIP related otherwise there is risk of app rejection. (See this answer).
UDPDATE1:
The documentation has been clarified for iOS8. The documentation can be read here. Here is a relevant excerpt:
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 push
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.
Although this was not made clear by the WWDC video, a quick search on the developer forums turned this up:
https://devforums.apple.com/message/873265#873265 (login required)
Also keep in mind that if you kill your app from the app switcher
(i.e. swiping up to kill the app) then the OS will never relaunch the
app regardless of push notification or background fetch. In this case
the user has to manually relaunch the app once and then from that
point forward the background activities will be invoked. -pmarcos
That post was by an Apple employee so I think i can trust that this information is correct.
So it looks like when the app is killed from the app switcher (by swiping up), the app will never be launched, even for scheduled background fetches.
You can change your target's launch settings in "Manage Scheme" to Wait for <app>.app to be launched manually, which allows you debug by setting a breakpoint in application: didReceiveRemoteNotification: fetchCompletionHandler: and sending the push notification to trigger the background launch.
I'm not sure it'll solve the issue, but it may assist you with debugging for now.
The answer is YES, but shouldn't use 'Background Fetch' or 'Remote notification'. PushKit is the answer you desire.
In summary, PushKit, the new framework in ios 8, is the new push notification mechanism which can silently launch your app into the background with no visual alert prompt even your app was killed by swiping out from app switcher, amazingly you even cannot see it from app switcher.
PushKit reference from Apple:
The PushKit framework provides the classes for your iOS apps to
receive pushes from remote servers. Pushes can be of one of two types:
standard and VoIP. Standard pushes can deliver notifications just as
in previous versions of iOS. 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.
To deploy this new feature, please refer to this tutorial: https://zeropush.com/guide/guide-to-pushkit-and-voip - I've tested it on my device and it works as expected.
Actually if you need to test background fetch you need to enable one option in scheme:
Another way how you can test it:
Here is full information about this new feature:
http://www.objc.io/issue-5/multitasking.html
I've been trying different variants of this for days, and I thought for a day I had it re-launching the app in the background, even when the user swiped to kill, but no I can't replicate that behavior.
It's unfortunate that the behavior is quite different than before. On iOS 6, if you killed the app from the jiggling icons, it would still get re-awoken on SLC triggers. Now, if you kill by swiping, that doesn't happen.
It's a different behavior, and the user, who would continue to get useful information from our app if they had killed it on iOS 6, now will not.
We need to nudge our users to re-open the app now if they have swiped to kill it and are still expecting some of the notification behavior that we used to give them. I'm worried this won't be obvious to users when they swipe an app away. They may, after all, be basically cleaning up or wanting to rearrange the apps that are shown minimized.
This might help you
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.
Source:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
For iOS13
For background pushes in iOS13, you must set below parameters:
apns-priority = 5
apns-push-type = background
//Required for WatchOS
//Highly recommended for Other platforms
The video link: https://developer.apple.com/videos/play/wwdc2019/707/
In IOS 4 if the application is closed by user manually then it is not launching again it crashes when launched and i cant do anything.
I am testing it on Ipod4
When i pressed the hard key of ipad twice and close the app manually then i am not able to start the application again.
how to terminate the application completely do i need to write something in
- (void)applicationWillTerminate:(UIApplication *)application
of appdelegate?
Seems like you have some serious issues with your code.
An application should support both going into the background and transitioning out of it into active state again, as well as terminating from the background once that is initiated by the OS, or by the user via the 'double home tap -> close' action.
Terminating the application forcibly through code is not supported and will actually result in apple rejecting your app when you submit it.