I am trying to call an endpoint after every 5 minutes and it's working fine with Timer when app is active but when app goes to background the Timer stops firing because timers don't work in background. Is there any possible way to achieve this even with the use of private api because i am not planning to upload the app on AppStore.
In a word, no. Apple goes to significant lengths to prevent apps from doing this sort of thing since it is a significant battery drain.
You might look at using the BGTaskScheduler API to schedule background requests that you would like the system to perform on your behalf, but you won't get a frequency anywhere near every 5 minutes.
I have a app that starts in the background, and since iOS 13 gets about 30s of background runtime using beginBackgroundTask(expirationHandler). I am trying to fetch data from an external service that takes about 40s to calculate its final output, so I need to extend background fetch and set a DispatchQueue for 40-60s later, or directly call the function in background 60s later.
I have looked up Background fetch, but I don't think it is adequate, for it fetched data forever (and on big time intervals), while I only need it 1 minute after the background calculations have finished.
I also looked at similar posts, which where outdated saying iOS could background task for 3 or 10 minutes as it could before iOS 13 and iOS 7
For context, the app receives a BLE packet in background making the app background task for about 30s, and sends the received data to a server which makes certain calculations, updating a GET http method which gives the app its final results
Clarification: I don't have access or can modify the server.
If there is not a way, is there any similar methods of doing the same thing?
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).
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
This question exists in different flavors on github, but this mine is specific. I'm creating an iPhone app that logs locations. I'm trying to log the location every 5 min even when the app is in the background and when the user is not moving. So far I've tried the following;
Use CoreLocation to fire the events - if the phone is stationary, the location events are not fired, so logging every 4 min in the bg does not work.
Use Perform Fetch to and read last location - this seems to fire when it pleases, can't get it to reliably fire every 5 min
Use a background task and NS Timer havent tried but seems feasable ** since this won't be going in the app store, is there a way to call a bgtask that spins up another bg task before it dies?
**** this app does not need to be approved by apple
If you need to do this for an in-house app - you're saying the app doesn't need to be approved by Apple - then you can set your app to be a VOIP app. In your info.plist file you set the corresponding background mode and then you can call the UIApplication:setKeepAliveTimeout to tell iOS at what interval you want some background processing time. Minimum interval is 10 minutes.