Detecting iOS app background termination by system - ios

What I'm trying to achieve is detecting when the system terminates an app while it is running in the background (not suspended). According to this article it can be done by process of elimination. One of the steps is deciding that user didn't force quit the app. I assume this is done by checking whether applicationWillTerminate was called. However, according to Apple's documentation this method can also be called by the system, so I'm not sure how it eliminates that option.
For apps that do not support background execution or are linked
against iOS 3.x or earlier, this method is always called when the user
quits the app. For apps that support background execution, this method
is generally not called when the user quits the app because the app
simply moves to the background in that case. However, this method may
be called in situations where the app is running in the background
(not suspended) and the system needs to terminate it for some reason.
Is it possible to detect background system termination, and if so, what am I missing here?

The App Programming Guide for iOS: The App Life Cycle says:
Suspended apps receive no notification when they are terminated; the system kills the process and reclaims the corresponding memory. If an app is currently running in the background and not suspended, the system calls the applicationWillTerminate: of its app delegate prior to termination. The system does not call this method when the device reboots.
In addition to the system terminating your app, the user can terminate your app explicitly using the multitasking UI. User-initiated termination has the same effect as terminating a suspended app. The app’s process is killed and no notification is sent to the app.
The above is consistent with empirical tests.
In that Reducing FOOMs in the Facebook iOS app article, they mention the force quit situation where the app did "receive a termination call the last time the app was open": That only applies if the app was actively running and the user force quit it. But if the user first returns to the home screen (or otherwise suspends the app) and then force terminates the app, you will not receive that termination.
Bottom line, if the app is suspended at the time it was terminated, I do not believe that you have any reliable way of knowing whether it was jettisoned due to memory pressure or because the user force quit. The force quit scenario contemplated in that FOOM/BOOM article clearly only applies if the app was running when it was force quit.

Related

Does the iOS open all apps after a reboot?

I've turned off my iPhone.
Then I turn it back on.
I have my phone connected to the macOS console. I filter by process:SomeAppName
And about 1 minute after reboot, I see app name appear with that filter.
Is that expected?
It would not “open all apps.” But certainly, it may open some apps (e.g., particularly certain “Background Modes” that are configured under a target’s “Capabilities”). See About the Background Execution Sequence, About the App Launch Sequence, Choosing Background Strategies for Your App, and WWDC 2020 Background execution demystified. None of these enumerate the specific cases where apps can be launched in the background automatically, but might be a starting point for your research.
FWIW, each of the target “Capabilities” » “Background Modes” has slightly different behaviors (i.e., some cause an app to be relaunched in the background triggered by some system event, others launch at the discretion of the OS, for example, if on wifi and/or when charging, and some gather data out-of-process and are delivered when the user launches the app). So you have to go through these individual “background capabilities”, one by one, and see which cause the app to be launched in the background and which do not.
But if an app has one or more background capabilities enabled, it could easily be relaunched. The “Background fetch” and “Background processing” are two prominent examples that can easily cause the app to be launched in the background without user intervention. The background location services can be configured either way (launch the app on location change vs. deliver location updates when the user next launches the app). It just varies for each of these background modes. As a general rule, Apple tries to offer out-of-process solutions where it can (to minimize power-draining launches of apps in the background), but provides methods to have the app launched in the background where needed.
In the past we would have concerned ourselves solely with apps being launched as a result of background capabilities. But, as About the App Launch Sequence says, iOS 15 complicates the “which apps might launch” question, as it has “prewarming”. So that might cause apps to launch in the background without user intervention, too.
You ask:
Would the app get killed/suspended after getting launched?
As a general rule, apps are never “killed”, unless you violate the contract of the background execution (e.g., fail to call the completion handler appropriate for that background service or block the main thread and get killed by the watchdog process). All of the various background modes have some mechanism to gracefully inform the OS that your background process is done and that the app can now be suspended again. But in those cases where the OS kills a misbehaving app, it generally no longer participates in future background execution, which is why it is so important to finish background processes gracefully.
Obviously, suspended apps can be evicted/jettisoned when memory is required by the OS. But this graceful termination is very different than an app being “killed.”
BTW, to clarify the observation that killed apps will not be launched by most background services, the old “App Programming Guide for iOS” gave us hints about how most background services will not be launched again, but that background location services might. The guide is no longer found on Apple’s site, but here is the relevant excerpt:
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.
The new documentation verifies that background location services “relaunch an app … even after the user force-quits your app.” But this older quote places that observation in a broader context.

iOS Background Mode: After running location updates in the background, the app never terminates

I'm running location updates in the background. All works well:
On significant location the app is launched in the background
- appDidFinishLaunching(options:) is called as expected.
I start LocationManager startUpdatingLocation() and startMonitoringSignificantLocationChanges()
Locations are collected correctly.
After some time, I call stopUpdatingLocation()
My program at this stage doesn't need to do anything and no further code is executed
At this point the program stays idle. applicationWillTerminate is never called again. Is this expected? I'd hoped the app will shut down again as no location updates are required.
What's the expected behaviour? Should the app shut down or should it stay idle forever?
Once this happens, then if a user user opens the app or a significant location is received again, then appDidFinishLaunching(options:) is NOT called, but instead applicationDidBecomeActive.
Is there any documentation I can follow that supports the expected behaviour?
Yes, everything here is expected. There's a deleted answer from J.D. Wooder that correctly linked the documentation: "Managing Your App's Life Cycle." As a rule, background iOS apps are not proactively killed. They are only killed when system resources are needed. This is unpredictable, and the app typically will not receive a applicationWillTerminate message when it happens (because the app typically is not running at that point, and it won't be woken up just to kill it). Your app should handled both a cold launch (appDidFinishLaunching) and a warm launch (applicationDidBecomeActive).
Restarting an app from scratch is expensive, so iOS prefers to keep recently used thing in memory if there's no resource pressure. Apps that are doing nothing are very cheap. to keep around.
Note that iOS 13 has grown much more aggressive in killing apps in the background, and that the large cameras on new phones are leading to memory pressures that kill apps more quickly as well, so don't get too comfortable with running in the background for a long time. But it's also very normal.
Please see the iOS app Life Cycle,
appDidFinishLaunching will call only when app Launch,
applicationWillTerminate - called when app terminate from background
applicationDidBecomeActive - Called when app comes to foreground from background

Is there a way to know when my app switches from Suspended to another state?

I'm having issues with my WKWebViews'cache being purged sometimes when a user hasn't been using my app for a while.
I guess, that's because iOS puts my app in Suspended and then a low-memory condition occurs so my app is purged.
I read Apple's documentation about The App Life Cycle - Execution States for Apps
Especially the part describing the Suspended state :
Suspended - The app is in the background but is not executing code. The system
moves apps to this state automatically and does not notify them before
doing so. While suspended, an app remains in memory but does not
execute any code. When a low-memory condition occurs, the system may
purge suspended apps without notice to make more space for the
foreground app.
Two questions here :
1) What does "purge" mean exactly ? The app is killed ? Or does it still appear on the app selector ( when double-tapping the home button )
2) Here we can see that there is no way to know when an app is going to be suspended. All right. But if a user comes back to the app, is there a way to know, then, that the app has been suspended ? I can't find any UIAppDelegate's method to do so, but there might be another solution ?
Purge - The purge command forces disk and memory caches to be emptied,
offering a ‘cold disk buffer cache’ which is similar to the state of
the operating system after a reboot.
Referenced from here
As per the documentation
applicationDidEnterBackground:—Lets you know that your app is now
running in the background and may be suspended at any time.
This is the only method which will let you know that method may will enter in Suspended State
also
application:didFinishLaunchingWithOptions: will let you now that
your app's launch process is almost done and the app is almost ready
to run.
The app is in the background but is not executing code
I think it's explained good by Apple, the app is still in memory but no background threads are executed since foreground app requires more resources. Maybe when memory is restored, your app can execute background code again if has not been killed by OS.
When low-memory condition occurs, you're app could be killed (purge).
Is there a way to know, then, that the app has been suspended?
When app is killed from OS, next launch is equal to a complete new restart of app. For this AppDelegate doesn't provide a method to achieve this. You could set a flag in UserDefaults when app goes in background and then make some logic on that flag.

How to avoid iOS app being terminated by system too often when in background

I'm building an iOS app for iOS 8 & 9 and I am facing the problem that when the app goes to background the system is terminating it after just 2 or 3 minutes.
My testing is easy:
I kill all running apps from my iPhone.
I restart my iPhone (to ensure no other apps are taking memory).
I launch my app.
I do nothing inside my app.
I press the "Home" button, moving my app to background.
I wait doing nothing else for 2 or 3 minutes.
I open my app again and surprise, the system has terminated it and now it is restarting as a new launch.
Some comments:
The app does not use CoreLocation in background neither any other service.
I've profiled the app, trying to understand if it is consuming too much memory. When moving to background, it consumes around 25Mb of RAM memory. I'm attaching a screenshot below.
This behavior has been tested on iPhone 5, 5s, 6, 6+.
In iPhone 6s and 6s+ seems to take a bit more time to happen, but still happens.
My question is: Do you know why would this be happening? anything I might not be considering or just forgetting?
I don't want to force my app to run in background by using CoreLocation or something similar. And I'm ok if the system kills my app eventually. What I don't want is that everytime I move my app to background the system terminates it.
Any hint or help will be appreciated.
Thanks,
All applications are automatically killed by the system
According the Apple documentation:
App Termination
Apps must be prepared for termination to happen at any time and should not >wait to save user data or perform other critical tasks. System-initiated >termination is a normal part of an app’s life cycle. The system usually >terminates apps so that it can reclaim memory and make room for other apps >being launched by the user, but the system may also terminate apps that >are misbehaving or not responding to events in a timely manner.
Suspended apps receive no notification when they are terminated; the >system kills the process and reclaims the corresponding memory. If an app >is currently running in the background and not suspended, the system calls >the applicationWillTerminate: of its app delegate prior to termination. >The system does not call this method when the device reboots.
In addition to the system terminating your app, the user can terminate >your app explicitly using the multitasking UI. User-initiated termination >has the same effect as terminating a suspended app. The app’s process is >killed and no notification is sent to the app.
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW1
You can track position but you will certainly see a blue status bar to indicate that an application use GPS tracking.
Maybe you can try to "wake up" your app in background with silent notification...
If it is not necessary to keep your app alive, trust the system...
Some error in inside your code. Please select debug Navigator before run your app... Now you can able to find your error..
Or too much memory also it will terminated..
Apps which are running in the background drain battery life faster, It gives you a bad perception of the device, instead of the app, because the average consumer has no idea that it's an app draining battery.
Thus iOS won't allow your app to run in the background, more than a few seconds. But there are some exception, an app can request extension to this by declaring that its starting a Background Task.
for more info you can check below links:
http://blog.dkaminsky.info/2013/01/27/keep-your-ios-app-running-in-background-forever/
http://www.speirs.org/blog/2012/1/2/misconceptions-about-ios-multitasking.html

Is there a way to know if and why iOS terminated your app?

I'm trying to debug an issue with my iPhone app that seems to be getting terminated while running on the device (it never happens in the simulator). The app is for iOS 8 only.
Once app enters the background (via the user hitting the home button) I start Significant-Change Location service. When a location updates happens while the app is suspended the system should put the app in the background where I then send an update to my server with the location. That operation is wrapped in a proper beginBackgroundTaskWithExpirationHandler to allow me the time needed to make the network call.
It appears though my app is getting terminated by the system because sometimes when I resume the app from the suspended state it is no longer in the view last seen when minimizing but is back at the root controller as if starting from a fresh launch. It does not appear to be due to a crash as I do not see it in the crash log nor is New Relic reporting such. The app is suspended though, not terminated, probably because it is getting launched again into the background from a location update.
The question is, is there a way to know that my app was indeed terminated by the system, and if so, for what reason(memory, exceeding background execution time, etc.) and at what time. Is there a log kept somewhere containing this information?
I'm under the impression I can not use applicationWillTerminate because the docs say this is not called when an app is suspend.
You may check in Devices page. (Shortcut is Command + Shift + 2)

Resources