How long does Apple permit a background task to run? - ios

I have to upload an array of image files to database, therefore, I stumbled upon Apple's background execution guide to make sure the app still uploads the data when user suspends or terminates my app.
But in the desciption, it says giving it a little extra time to finish its work if we call beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: to start a background task.
How long is little extra time precisely?

Correct me if I am wrong, but I have stumbled upon a perfect article from Xamarin that discusses iOS backgrounding feature.
I will simply break down to two parts, ios pre 7 and ios 7+:
iOS version pre 7
The answer is simply 600 seconds (10 minutes), reason is provided by
the article above.
iOS version 7+
The answer is that the time system allocates you is opportunistic. You
will have to use #Gary Riches's suggestion
NSLog(#"Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
to find out. The reason for it being opportunistic is the way iOS 7+
handles background tasks is completely different, certainly optimised. To
be exact, It has an intermittent behaviour, and therefore, if you need
background tasks such as downloading a big chuck of data, it will be
much more effective if you use `NSURLSession` instead.
However, in my special case, I am uploading one single object that contains one file to be exact. I do not have to consider NSURLSession for uploading a small amount of data. And besides, it's uploading task, it can take as much time as it wants. :-)
For these TL;DR visitors, the answer above should be sufficient. For more details, please refer to the article above.

The amount of time will differ based on many different variables, but the value can be checked by referencing the backgroundTimeRemaining property on UIApplication:
NSLog(#"Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);

If you want to upload your files when app is in background, you should use Apple's background service. iOS will give your app time of approx. 3 minutes (based on some experience) for completing your task and then it will kill your app.
Apple allows longer run of the app in special cases. For that you will need to use UIBackgroundModes in your info.plist file. For more info on these special cases see table 3-1 on this link.
Here is a nice article that describes background task run time and how to achieve long running background task in iOS.

Theorically, you have 2/3 minutes to close the tasks you want to do in background, if you don't do it, your app can be killed.
After that, you can call 'beginBackgroundTaskWithExpirationHandler 'and you have to be prepared just in case the 'little extra time' that Apple gives is not enough for the tasks you need to finish.
EDIT:
When an iOS application goes to the background, are lengthy tasks paused?:
From the documentation:
Return from applicationDidEnterBackground(_:) as quickly as possible. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method doesn’t return before time runs out, your app is terminated and purged from memory.
From Raywenderlich:
'Again, there are no guarantees and the API documentation doesn’t even give a ballpark number – so don’t rely on this number. You might get 5 minutes or 5 seconds, so your app needs to be prepared for anything!':
http://www.raywenderlich.com/29948/backgrounding-for-ios
How much time you get after your app gets backgrounded is determined by iOS. There are no guarantees on the time you’re granted, but you can always check the backgroundTimeRemaining property of UIApplication. This will tell you how much time you have left.
The general, observation-based consensus is that usually, you get 10 minutes. Again, there are no guarantees and the API documentation doesn’t even give a ballpark number – so don’t rely on this number. You might get 5 minutes or 5 seconds, so your app needs to be prepared for anything!

It is not fixed: in Xcode 10 and Swift4.1
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
print(UIApplication.shared.backgroundTimeRemaining)
}
OP1: 166.13057912699878 mean approx 2.7 min,
OP2: 177.4997792619979 mean approx 2.95 min

Related

iOS Background service limitations

I would like to know if there are limitations regarding how often I can execute something in the background. I found this library : background fetch and it says that on the iOS part I cannot execute it more often than 15 minutes.
Are there workarounds for this?
My purpose is to check in the background the available Bluetooth devices detected and to send them to a database.
I only have experience in android and I'm not sure how to convert it to iOS or if it is possible.
Yes, there are limitations imposed by iOS. It will decide when your app is given time to execute background tasks such as a fetch of web data. It can be more frequent than 15 minutes but on average it may be every 20 minutes at best. It might be two hours or more. We are not privy to the algorithm and cannot predict the result.
Known factors are power state, how well your app conforms to the rules and gets its work done in the time allotted, and some measure of how (and when) the user uses your app. Low battery? Fewer background tasks allowed. User never uses the app before 8AM? Few fetches called overnight. It's all beyond developer control.
A developer can use a timer to trigger a routine task but it's only relevant if the app stays active in the foreground.

Background Fetch Enumerations

In iOS the outcome of a background fetch could be one of the following:
UIBackgroundFetchResultNewData
UIBackgroundFetchResultNoData
UIBackgroundFetchResultFailed
In what way does iOS care about the outcome?
I understand that a fetch that lasts too long (I believe 30 secs or more) is penalized by giving less fetch opportunities to the app.
Does any of the above, specifically NoData and Failed have repercussions as well?
Or is this just for internal processing?
Why not just return UIBackgroundFetchResultNewData every time?
The precise algorithm used by Apple is not described, but in the iOS Application Programming Guide Apple states,
Apps that download small amounts of content quickly, and accurately reflect when they had content available to download, are more likely to receive execution time in the future than apps that take a long time to download their content or that claim content was available but then do not download anything.
It seems that iOS observes your app's behaviour. If it claimed that new content was available (returned UIBackgroundFetchResultNewData) but it did not actually perform a network operation it may receive less frequent background fetch opportunities. It pays to be honest.
I also seem to remember reading somewhere (but can't find a reference now) that iOS can use the completion value to determine the times of day when your server may have new content (For example, if the fetch around 1am consistently returns new data and the fetch at 6pm consistently doesn't, iOS may be more likely to perform a background fetch for your app at 1am).
You should aim to complete the fetch as quickly as possible, but do not call the completion handler until the fetch is complete or your app will be suspended without completing the download. You can also use beginBackgroundTaskWithExpirationHandler to get more time, but your app has a limit of 180 seconds, total, of background execution per 'backgrounding' (ie. If the user brings your app back to the foreground and then suspends it again the 180 seconds is reset).

Should I call setMinimumBackgroundFetchInterval every time the app restarts?

I developed an app that uses background fetch. I set the minimum interval between updates to minimum:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
I thought that this value is saved by the system, so I don't have to set it again when/if the app restarts.
However, I've just noticed that the last background fetch on one of my devices was two weeks ago. I know, that the interval between updates can vary, but I don't think that two weeks is normal. Especially considering the fact that it worked for several months, calling background update every 20-30 minutes.
Unfortunately, I couldn't find a way to get the MinimumBackgroundFetchInterval to check my theory (does anyone know how to get it by the way?). I only checked application.backgroundRefreshStatus, and it is equal to UIBackgroundRefreshStatusAvailable, but I think (I'm not sure) this only means that the user allows the app to use background updates.
Well, it turned out that NO, we don't need to call setMinimumBackgroundFetchInterval every time the app restarts.
I had an experiment: I set it to UIApplicationBackgroundFetchIntervalMinimum (turned the background fetch on), then shut the app down manually (via the task manager) and then restarted it, but didn't call to setMinimumBackgroundFetchInterval. The app continued to perform background fetches as it used to.
I hope, that this information will be helpful for someone, since it is not explicitly stated in the documentation (at least, I didn't see it). As for me, I have to find another possible reason why my app didn't work for two weeks.

How often is background fetch executed in iOS?

In iOS 7, a background fetch mode is supported for apps to fetch data when the app is not frontmost:
When it is convenient to do so, the system launches or resumes the app in the background and gives it a small amount of time to download any new content.
My question is: how often is the background fetch code executed?
If I set the minimum interval:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:10];
Does it get execute every 10 seconds, or maybe once a day? What kind of interval should I expect, generally?
There is no way for you to know how often, it is up to things like the users usage pattern, device battery and whatever else Apple has in their algorithms...
The minimumBackgroundFetchInterval can be used to specify that your app doesn't need to run fetch so often, it does not make the fetch happen more often. You also have the minimum possible value in UIApplicationBackgroundFetchIntervalMinimum, which is what you can use if you want the background fetch to run as often as possible (but still no guarantee on how often it will actually run).

swift/ios refreshing app data when in background

I'm writing a iOS/Swift application which reads data from a REST service each X minutes and updates the UI accordingly.
Now I would like that when the app is put in the background, a task keeps being invoked at X minutes intervals reading from the REST service and, in case the data just read satisfies a given condition, show a notification prompting the user to bring the app back to the foreground.
In my searches I've read that during applicationDidEnterBackground event, I should start a task with beginBackgroundTaskWithExpirationHandler.
The problem is that, if I've understood correctly, this allows a maximum of 10/15 minutes after which the app is terminated if the task is not stopped with endBackgroundUpdateTask, while I want the task to keep polling the service indefinitely (at least until the user disable it from the app's settings)
My question is:
How is this kind of functionality performed normally? Do some common solutions or best practices exist for the solution of such a problem?
Use iOS Background Fetch feature where you can specify minimum background fetch interval. But actual interval between successive invocation of your code will be determined by iOS framework. For details checkout this link: http://code.tutsplus.com/tutorials/ios-7-sdk-working-with-background-fetch--mobile-20520
I use this approach in my app and I think it is a preferred way of doing.
You can use a local notification that can be presented from the background in case your condition is met.
Correct, iOS will eventually shut down the background process, you can't enforce continuous background activity. Use the backgroundTimeRemaining property to check how much time your application has left and try to handle it as gracefully as possible by calling endBackgroundTask so that iOS does not force kill your app.
As a solution, you could think about using remote notifications with with content-available : YES, which runs the didReceiveRemoteNotification
Have a look at the Parse.com Their local datastore is an abstraction for what you are trying to acheive.
By the way, is it really necessary to refresh in the background. If call is relatively quick, there is no need to refresh until the user open's the app. Background processes like that, using the net can be quite battery consuming when the user are not on a Wifi. So consider the use case carefully!

Resources