Distinguishing whether an iOS app running in background is terminated by iOS or user - ios

My iOS app is running in background (with location services permissions) and I am trying to determine if the app is terminated by the user or they system. In the case of a user terminating with the app switcher, I'd want to clean up some location region monitoring (ideally immediately, or less ideally on a reload of the app), because I assume the user wants a clean termination. In the case of a system termination, I want to leave the region monitoring in place. The problem is that in both cases (for an app running in background - as opposed to suspended, where one can check if the state change to suspended occurred before termination -), applicationWillTerminate is called for both a user and system termination. In this particular case, that's problematic because I'm unable to determine whether it's system or not. Is there any way to make this differentiation? Or, perhaps another angle: how can one detect if the previous app termination occurred due to a crash (in this case, though not as ideal, at least clean up can be done on reload of the app).
I should clarify as an edit, that what I mean by user force quit, is that the user swipes up in the multitasking screen. This generates a call to applicationWillTerminate. A force quit by holding down the home button after holding down the power off button, doesn't call applicationWillTerminate, but I'm not concerned about this case - What I would ideally like to determine is if the user terminated in the multitasking screen (or whether the os killed that app for, say, memory issues).

Related

Resume downloads on iOS between lifecycles

I am trying to make sure that if my background download on iOS stops for whatever reason (app is killed by the system, stopped by the user from the multitasking screen, crash?) will continue in the next lifecycle.
So far I have found that the documentation for NSURLSession clearly differentiates between two clear use cases: terminated by the system ( in which case downloads will continue smoothly in the background and the system will wake up the application when the download finishes ) or killed by user (and which case everything is lost - or is it? ):
If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.
This is the line that bugs me. What transfers can begin again? I thought they were lost. Does it refer to the fact that I can start another download session?
Also, I could not find any info on what happens with downloads that are suspended by the system because of the network connection type. For instance if allowsCellularAccess is set to false, and my app is terminated by the system, will it still continue when it moves to an allowed network?

App terminates after about 5 mins after the pressing lock button

While my app is in the foreground if a user presses the lock button the app will resign from activity but should still be ready to start again when the user unlocks their phone. After about 5 mins or so my application ends up being terminated and when they unlock their phone they are back on the home screen. Is this expected behaviour? As far as I know I havn't experienced this situation until I started a new project. Am I doing something wrong here or forgetting some sort of setting?
The Operating System can terminate your application at any time to free resources for other processes that may need them or to conserve battery life.
"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."
(Source: Apple Developer - "The App Life Cycle")
To minimize the likelihood of this happening to your application, look at what processes are running and do what you can to stop/ pause them while the application is not in the foreground.
Regardless how quickly this happens, it's important to design your application to handle the situation where it may be terminated in the background as this is something that can and will happen. Save state and critical information, such that on next launch the user can continue where he left off.

Core Bluetooth - Performing Long-Term Actions in the Background

This is from the Core Bluetooth Background Processing for iOS Apps section found in official docs:
Performing Long-Term Actions in the Background
Some apps may need to use the Core Bluetooth framework to perform
long-term actions in the background. As an example, imagine you are
developing a home security app for an iOS device that communicates
with a door lock (equipped with Bluetooth low energy technology). The
app and the lock interact to automatically lock the door when the user
leaves home and unlock the door when the user returns—all while the
app is in the background. When the user leaves home, the iOS device
may eventually become out of range of the lock, causing the connection
to the lock to be lost. At this point, the app can simply call the
connectPeripheral:options: method of the CBCentralManager class, and
because connection requests do not time out, the iOS device will
reconnect when the user returns home.
Okay, we have an app which locks/unlocks doors as appropriate... So as pointed out, this works when app is in the background (most likely in the suspended mode). Now, lets move on (with quoting docs):
Now imagine that the user is away from home for a few days. If the app
is terminated by the system while the user is away, the app will not
be able to reconnect to the lock when the user returns home, and the
user may not be able to unlock the door. For apps like these, it is
critical to be able to continue using Core Bluetooth to perform
long-term actions, such as monitoring active and pending connections.
So, if the user was away from home for a few days, and app has been terminated by the iOS, we will have to implement state preservation and restoration, so that iOS relaunch the app when connection request is detected, and let the app to unlock the door. Related quotes:
In the case of the home security app described above, the system
would monitor the connection request, and re-relaunch the app to
handle the centralManager:didConnectPeripheral: delegate callback when
the user returned home and the connection request completed.
This all make sense, but pay attention to this part again:
Now imagine that the user is away from home for a few days. If the app
is terminated by the system while the user is away, the app will not be able to reconnect to the lock when the user returns home, and
the user may not be able to unlock the door. For apps like these, it
is critical to be able to continue using Core Bluetooth to perform
long-term actions...
Does this means, if the app is forcefully killed by the user at some moment while he was away from home, that this will work as well ? Means when user comes home, the door will unlock anyway, or he must manually relaunch the app to unlock the door?
I am asking this, because of how relaunch of terminated apps works. It is not the same when user kills the app, and when iOS kills the app which supports background execution:
Apps that support background execution may be relaunched by the system
to handle incoming events. If an app is terminated for any reason
other than the user force quitting it, the system launches the app
when one of the following events happens...
Source
So once again, if the user was away for a few days and he has closed the app by double tapping Home button and dragging up, will he be able to enter his home without manually relaunching the app?
No. If the app is forcefully killed by the user then it will not be woken up again. The only scenario where it will be woken up is if the app was terminated by iOS itself, which will happen sooner or later when the app has not been it the foreground for a while. It will also not be relaunched if the device is rebooted.
Having said that, from my experience with Core Bluetooth I have come to the conclusion that State Preservation is way too unreliable. I would believe that the use-case that you are trying to implement will not work well enough, which is ironic since it is exactly the use-case that Apple is promoting it their documentation.
For example, you will have issues with the following:
State restoration will only relaunch your app due to bluetooth related activity if the event originates from a peripheral accessory that you are communicating with, such as connect/disconnect events and characteristics notifications. For other events, most importantly general bluetooth-state-change events, your app will not be relaunched and notified of this. The reason why this is so bad is because any bluetooth-state-change events will cause all pending connections to be tossed, meaning that your pending connections to the door lock will be lost. However, since your app is not relaunched to be notified of this, then it effectively means that your application will still believe that the connections are still pending when in fact they are not. Since your application is terminated at this time, the only way for it to wake up again is by having the user manually launch it again (or alternatively “hack” other background modes for this purpose, which will NOT work very reliably either).
This scenario happens if the user toggles Flight Mode, toggles Bluetooth, power cycles the iOS device, or any other undefined reasons that many cause state changes… And it is very unlikely that a bluetooth-state-change will not happen if "... the user is away from home for a few days.".
This "issue" has been reported by me and others multiple times, but Apple does not appear to want to fix it for some reason.
Apart from this, many other issues exists as well, such as the XPC connection being interrupted at different times for no apparent reason. I have also noticed that the pending connection can go into “limbo” mode where the peripheral state gets set to Connecting, but in fact it will never connect unless you cycle the connection state. Etc, etc, ...
/A

Get location update when app is terminated Swift [duplicate]

My application requires periodic location updates (every 10 minutes). In foreground and background (app not terminated) the application is working correctly. But the problem starts to occur when the app is terminated by the user.
I tried using this tutorial http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended .
It works only when user's location is changing because of startMonitoringSignificantLocationChanges. But I need locations in terminated state even if user is not changing its location.
Also, I have tried most of the stackoverflow questions but most of them gets satisfied with startMonitoringSignificantLocationChanges. But in my case it won't be enough to fulfil the application needs.
If a user terminates the app the system no longer grants it the same privileges. Background fetch operations and background location will not get executed until the user decides to start up your app again. The system recognizes this a user choice to not have this app running in any way again.
This isn't like the world of Android where an app can do as it pleases. Apple prefers user choice over what an app developer wants. This is of course good and bad as a developer. You need to provide the user with useful information about what your app is doing in the background so that they will allow it to run without terminating it. If they do terminate it, there is nothing that you can do.

Implementing Periodic Location Updates in iOS even if app gets terminated

My application requires periodic location updates (every 10 minutes). In foreground and background (app not terminated) the application is working correctly. But the problem starts to occur when the app is terminated by the user.
I tried using this tutorial http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended .
It works only when user's location is changing because of startMonitoringSignificantLocationChanges. But I need locations in terminated state even if user is not changing its location.
Also, I have tried most of the stackoverflow questions but most of them gets satisfied with startMonitoringSignificantLocationChanges. But in my case it won't be enough to fulfil the application needs.
If a user terminates the app the system no longer grants it the same privileges. Background fetch operations and background location will not get executed until the user decides to start up your app again. The system recognizes this a user choice to not have this app running in any way again.
This isn't like the world of Android where an app can do as it pleases. Apple prefers user choice over what an app developer wants. This is of course good and bad as a developer. You need to provide the user with useful information about what your app is doing in the background so that they will allow it to run without terminating it. If they do terminate it, there is nothing that you can do.

Resources