iOS Background service limitations - ios

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.

Related

Execute a Task after specific time, even if app is in background on iOS using Swift

I have a VPN-Client app that asks the user to pause the connection for 5, 30, and 120 Minutes. The user probably leaves the application to do some work outside of my app in this period, therefore I need to Reconnect the app even if is in the background.
I tested these ways:
UIApplication.shared.beginBackgroundTask: It only leaves the app unsuspended for 30 seconds.
DispatchQueue.global(qos: .background).asyncAfter: It waits to app enter the foreground to toggle.
Thread.sleep in Background Thread: This waits to launch as DispatchQueue
Local Notification: Unfortunately it does not support silent mode as APNS.
My problem with possible ways:
Using APNS and Scheduled Push Notification` to send a silent message: This way probably works, but I prefer to handle it without a server.
Using Background Fetch from Capabilities in Background Modes: I searched a lot about this, and I think it was used for background app refresh and cycling tasks that should be run every day, hour, etc. Therefore, my case can't be used, or it's not efficient at all.
Using Background processing from Capabilities in Background Modes: I searched a lot about this too, I didn't quite catch that it can be used once, or this should be used in a cyclic way as Background Fetch. and my task to reconnect is not that heavy and long to use this strict feature that many times apple mentioned using alternative ways if possible.
Apple only allows a very limited set of app types to run in the background:
Music streaming apps, turn-by-turn navigation apps, VoIP apps, and maybe one or 2 more. (I haven't looked at this in detail for a couple of years so my info is a little stale.)
They do support various tasks like background downloading that the system performs on your app's behalf, but you want your app to re-launch after the designated period and start running again. (Even if the user just locks their phone while your app is paused, the app won't get any CPU time and may be terminated without warning.)
In short, I suspect you are out of luck.
It seems like a VPN app is another class of app that should get "always running in the background" status.
If you are a licensed Apple developer I suggest using one of your pre-paid support tickets to ask about OS support for what you are trying to do, but I have a feeling the answer is going to be "no dice."

How to run a large on demand sync on an ios device?

I have been looking at the options available to do a user driven on demand sync of a large data set (roughly 1gb) to a iOS device from a central server. The intention is that the user will go offline some time after the sync is complete, and use the app in offline mode for some time afterwards. However, I am running into a lot of iOS restrictions that seems to prevent this.
The beginBackgroundTask does not allow enough time to complete a sync before its suspended as it only allows up to 30 seconds of background processing. I have seen a few references to this being increased by using audio or gps functions however neither of these are applicable to my situation.
The BGProcessingTask apis are at the systems discretion as to when they are run, so are not sutiable for an on demand process.
The NSURLSession api allows for downloads to occur while the app is suspended, however the problem with this api is that it requires the server to extract all necessary data to a temporary file before it can be downloaded, this process can take several minutes. This introduces the problem where the application can be suspended before the server has completed generating the file to download.
I'm aware a background push can be used to wake the app and start the download using the NSURLSession api if the app has been suspended, however this approach places the execution of the download back at the discretion of the OS which can lead to significant delays in the sync actually starting, which makes for a rather undesirable solution.
Its also worth noting that precalculating and caching the data to download in advance is not a viable option due to the number of updates that occur and different permutations of data depending on permissions assigned to each user.
With that, are there any apis that I have not considered, or any misinterpretations to the ones above that would allow me to achieve an on demand sync of such a large data set?
It seems iOS is missing the ability for a user to explicitly opt in to starting a long running process and allow it to continue till complete. I'd assume some other enterprise apps would have come across a similar problem before, and I would be gratefull to see how its been solved.

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).

Periodic background synchronization

Im quite new to iOS programming and now want to implement a periodic background synchronization to synchronize my server data with client data. What I want to achieve is comparable with Androids SyncAdapter where you can define a time interval (for example each 30 minutes) and the system will trigger the defined task automatically in the background.
Until now I could not find such mechanism for Swift 3.0 so I need to ask if somone has experience or some hints for me how I can achieve this.
What I want to do sounds quite simple:
When the app starts for the first time the app should setup a sync manager which automatically triggers a background task every 30 minutes. The background task is responsible to synchronize server and client data (using Alamofire).
How can I do that?
There is an iOS feature called BackgroundFetch, which you can set up for
regularly downloads and processes small amounts of content from the network
You can setup a minimumBackgroundFetchInterval.
In contrast to the mentioned Android feature, this interval is not guaranteed though.
The OS does some heuristic in a blackbox. It rewards you for using a "reasonable" (to the OS) CPU time/ power consumption and also for being used often by the user. On the other hand you get punished for draining the battery or (even worse) never being used/opened by the user.
See: Apple Sample and Apple Docs
Update: Since iOS13, BackgroundFetchis deprecated.
There is a similar, new API named BGTask, BGAppRefreshTask is the equivalent to deprecated BackgroundFetch.
See Apple Docs
Alternatively, depending on your needs, you can post a Silent (push) Notification whenever the users data changes on server side. A silent push wakes up your app without notifying the user, so you can fetch data and maybe inform the user by scheduling a local notification.
See: Apple Documentation
You can't. Apple doesn't allow 3rd party apps to have regular background time like that. You'll need to come up with another approach like implementing a silent push notification from your server when new content is available.
As #ekscrypto points out in their comment, you can use Background fetch to load small amounts of data when the system decides to fetch it. However, you don't have any control over when that fetching takes place. Search on "Fetching Small Amounts of Content Opportunistically" in the Xcode help system for more information.

Android Services equivalent in iOS Swift

I am looking for something that is equivalent to Services in Android. As far as I have searched I haven't found anything useful. I found Background Fetch but according to my understanding it cannot be used long processes.
Here is what I want to use it for.
fetch a list of twitter user ids from our web server then auto-follow those usernames in background. As there are limits in Twitter API, so the process will be long possibly 3-4 hours. Is this possible on iOS?
There is no long-running background mode for continuous execution of apps in iOS.
This doesn't really sound like the right task for a mobile device. Running a 3-4 hour background job would be bad for battery life.
You can implement the function on a server somewhere and use push notification to send updates to the device.
An Android Service use case that is often cited is a background music service, which I have implemented as an exercise. It is not a given that a long running task actually will consume a lot of battery. Rather, it appears Apple is guaranteeing that such an event cannot happen through API design.

Resources