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.
Related
I Did lots of BG tasks in the past, But Trying to get data when app is killed (Even when user is giving Always permission) seems not to work.
I wonder if there is a solution for that.
To make things clear, I am not talking at the moment when app change from Active or Background even to suspended mode. I'm talking about if the user is using the app and set permissions but then kills the app and after that i need every hour to get data from the user and send data to them.
Is there a way to do that?
Can a Today widget help me with that? Does a Today widget "lives" all the time and i can get that from it 24/7?
Whet is working is CLLocation manager. This is working even when the app is killed. But only when the user is changing a location.
I need that to work when the user is in the same place also.
Non of the other methods work. Not BGTask (I need every hour on the hour and not when apple decide to do things), Nor Silent Push Notification for some reason (Regular ones work, but i Don't want to bother the user with a push every hour just for getting and sending data).
Sorry there is no code to show as this is a very general question. But i think that is very important one to many people and can't find an answer for that.
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).
In my app I'm registering a NSSystemClockDidChangeNotification notification in AppDelegate method application:application didFinishLaunchingWithOptions:options.
Posted whenever the system clock is changed. This can be initiated by
a call to settimeofday() or the user changing values in the Date and
Time Preference panel. The notification object is null. This
notification does not contain a userInfo dictionary.
Month ago it was working fine, but these days every time I suspend my app, lock my iPhone and leave it 2 minutes to pass, when opening the app, the selector method is called, which is weird to me. I didn't change the system or time, I just let the device idle.
Can anyone help me understand this? I just want to execute some code when the user manually change the system time, just in that case (tried with UIApplicationSignificantTimeChangeNotification but that doesn't help).
Like that: Getting iOS system uptime, that doesn't pause when asleep
But remember, this solution will fail sometimes because of out-of-sync when system tries to update time from NTP server when the Internet connection is not reachable.
This answer is a bit late but this is what the apple support team replied when I ask a similar question:
Part of the question I asked:
Could it be possible for the OS posted [this notification] if the
time/timezone has not changed in the device?
The answer I got from them:
Absolutely [1]. It's common for a notification like this to be posted
redundantly. In some cases it's triggered by a state change you can't
see. For example — and I haven't tested this theory, so it's just an
example of how this sort of thing can come about — this notification
might be posted if the system's giant list of time zone info has
changed. So, the time zone state has changed, but it's not something
that affects your app.
But in other cases, a notification might be truly redundant (-: iOS
is a complex system and in some cases this complex machinery generates
redundant notifications, and there's no need to filter them out
because…
Your app should respond to such notifications be refetching the info
it cares about and updating its state based on that. If this update
is expensive, keep your own copy of the previous state, compare the
current system state to that, and only do the update if the stuff you
care about has actually changed.
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
I was just wondering if it was possible to consistently update the data for my app every 60 seconds.
I have the following code right now:
NSTimeInterval testTime = 60.0;
[application setMinimumBackgroundFetchInterval:testTime];
However when testing on the simulator, the app initially grabs the data upon install, and then doesn't do anything else. My web searches tell me that iOS determines when to actually trigger background fetch.
That being said, is there anyway to consistently have background fetches occur for the user? Like say, for every 1 minute? My app's big selling point depends on the latest up to date information. I think it's possible, as apps like Gmail,twitter, SnapChat are always checking for new data...
Thanks
There is no way to achieve this using background fetch. You can only force this behavior using push (silent or otherwise), sending a push message to each device once every period of time.
Allow me to say, this is a terrible design. Polling is a terrible design for mobile apps. You should implement proper push notifications, notifying the user of new content, and loading it in the background as the OS deems possible.