Handling large number of API requests in iOS App (Not using Alamofire) - ios

How to handle the states in which the app goes into foreground setting off a number of requests (around 3-4 minimum) because that information is required in the app, and then going to background?
What I have tried is to use a RequestManager to suspend the URLSessionDataTasks when app goes into background and when app resumes, resume those tasks again. But I don't see this working very well.
Is there a standard way to go about this?

Suspending tasks won't work, because the session no longer exists if your app gets jettisoned for low memory.
The most straightforward approach would be to use a download task in a background session, then read the resulting temporary file when it finishes downloading. Download and upload tasks in background sessions are the only types of tasks that can survive your app getting jettisoned while in the background because of memory pressure.
If you absolutely must avoid downloading while the app is in the background (why?), you could create a download task in either a foreground or background session, then stop the download tasks by calling cancelByProducingResumeData: when your app gets backgrounded. You can later continue the request by calling downloadTaskWithResumeData:.
There is a rather large caveat with that approach, though, which is that the resume data portions of the API are not nearly as well tested as the background downloading portions. Case in point: in every version of iOS 10 from the first beta until 10.2, support for resume data was completely broken. (There is a rather horrific workaround, in case you choose to go down that path.)
So I would recommend the first approach unless you have some contractual or legal obligation not to do so.

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.

Uploading video files while iOS app is in background?

I'm currently working on an iOS app which involves recording and uploading videos (from the built-in camera) to a server.
It all works reasonably fine and dandy, but for a new version, the customer has requested a new feature: continuing this process without needing the app to up on the screen, and active.
At present, you record a video, it's stored as an MP4 on the file system, and a background thread uploads the file to the server. This all happens while the app is open, culminating in a screen which essentially tells you to wait until the process has finished.
If you press the home button to "minimise" the app (I'm not fluent in iOS terminology, forgive me), currently all upload processes are paused. The customer wants to have it so that you can minimise and do something entirely different as this process continues, with a notification being shown once the uploads are complete.
My understanding is that iOS offers a few special cases for downloading, streaming music and location stuff.
Supposedly once upon a time you could obtain ten minutes or so of background time while your app was minimised to finish tasks - after which time iOS would forcefully pause everything until the app was front and active again. This apparently has been changed in newer versions of iOS meaning you can't rely on a specific figure anymore - but ten minutes wasn't really good enough anyway.
I can think of hacky ways of abusing the above features but I'm half-concerned Apple might discover this during the iTunes submission process. Really I'm looking for a cleaner method - how do I continue uploading videos while the app is minimised?
I am assuming there's a solution - Dropbox can handle this situation?
Surprisingly I got somewhere with this, despite quite a few guides suggesting it was virtually impossible and even Dropbox admitting it has to do a hacky location-based thing.
The code was utilising the NSURLSession class, and for uploading, you use its uploadTaskWithStreamedRequest() method, passing an HTTP request and getting a NSURLSessionUploadTask instance in return.
What wasn't immediately clear to me, however, was that "resuming" that task led to files being uploaded independently from the rest of the app, i.e. when the app is minimised, this task continues until it either completes or iOS forces it to pause.
In a sense I had already achieved what I asked for without realising, however this task can still be interrupted by iOS after a few seconds. The rest of the app is also paused, so communication is hampered until the app is brought back to the front again.
The trick is these two methods:
uploadTaskID = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({})
and
UIApplication().sharedApplication().endBackgroundTask(uploadTaskID)
with these in place, any code after the "begin" function will run regardless of whether the app is minimised, and will do so until the "end" function is called. With a bit of tweaking, I've been able to get files to upload sequentially and post a notification when the process is done.
I haven't seen this solution be hinted at so it might be a bad idea, but it seemingly works.

Background Upload too slow using NSURLSession in iOS

I am trying to upload a huge video file using NSURLSession background upload task. I break the file into chunks of 256Kb and upload them. When the app is in foreground the upload of chunks happen real quick (5 seconds for 256Kb). But when the app is pushed to background though the upload continue to happen the speed of it is reduced crazily (5 minutes for 256Kb). Any thing wrong here or any thing I need to take care of ?
When your app is in the background, the user has indicated that whatever it's doing is not as important as something else. The system will throttle the background network tasks because they are not as important.
There is also the discretionary property on the configuration object which will, among other things, prefer to download when connected to power and wi-fi. If the download is initiated while the app is in the background, the download will behave as if the discretionary flag were true.

guaranteed delivery for uploads after network reconnect, even if my app is not running

I'm spec-ing an iOS app (which will be built outside of our company) which will upload a user's data entry to a server. If the device is not connected to the Internet, we'd like to save data on the device and upload it when the network is re-connected. (The app will primarily run on iPod Touch devices that will be disconnected most of the time).
If the user unlocks the device and re-opens our app after the network is reconnected, then uploading to the server should be easy because the app is running.
But what if the app is not running, where "not running" can mean one or more of:
device was power cycled
user has locked the device and it's sitting in his pocket
app crashed
user exited the app
user started using other apps so our app isn't running in the foreground anymore
are there other cases?
In the cases above, is there a way (ideally a battery-efficient way) to ensure that local data is uploaded soon after Internet connectivity is restored? Is the answer different depending on which of the cases above caused the app not to be running?
And is there a minimum iOS version the device will need in order to enable some (or all) of the above not-running cases to still upload when the app is not running?
My apologies if these are obvious newbie questions-- I'm not an iOS expert.
There is an interesting technique that is used by among others Instapaper and News.me(the pioneers of this technique) where you use region monitoring to initiate background downloads or uploads. Marco (Instapaper) blogged and talked (in episode 80 of the Build and Analyze podcast) about his communication with Apple so it should be a allowed in the App Store.
In brief the technique is that you set up certain regions (geofences) like "home" or "work" and respond to the locationManager:didEnterRegion: (and similar) callback(s). Your app will wake up from the background once you enter the pre-specified region and you can check to see if there is any data to upload.
This technique won't guarantee that the data is uploaded when the network reconnects but it will allow your app to automatically upload the information when the iPod Touch users gets home to their WiFi network.
That should most likely be at least once a day which may or may not be frequent enough for you. You could add a timestamp to when the initial upload was attempted and send that along the upload once it succeeds to get the correct order of events (data entries) on your server.
There is no way to ensure this. If your application is "not running" (by the definition described in your question), it will not be capable of responding to a change in the device's network status. It should be setup to resume upload operations the next time the application runs again.
EDIT:
Some of the cases you've described may indeed provide different opportunities for your application. Specifically, if the user "exits" the app by pressing the home button or launches another app in the foreground, your application may continue to run the in the background and could potentially respond to a change in network reachability.
The nature of what may be done in the background and for how-long is well documented, and supported by any version of iOS that supports multi-tasking. I recommend you review the documentation pertaining to App States and Background Services.
device was power cycled --> really NO WAY of resuming, unless you open the App!!!
user has locked the device and it's sitting in his pocket --> apps applicationStatus is UIApplicationStateInactive but it is running in the background. You still are able to react to notifications and i.e. accelerometer events. Try the Reachability Class and Log the changes!
app crashed --> NO WAY, unless opening the App
user exited the app --> App is sitting in the background. There you have a maximum of 10 Minutes Restriction of fully using your App (like the App "Pastebot" does)
user started using other apps so our app isn't running in the
foreground anymore --> Same as user exited the app
On multitasking Apple says the following:
Real multitasking only for certain kinds of usage, as there is Audio Background playing, VOIP (like Skype), navigation applications
All the other apps can request a specific amount of time after the app is closed/in the background, to finish certain tasks (as sending an email, sms or uploading/downloading important data)
Important Quote from dev docs:
Your app delegate’s applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds.
If you're building a restful API then I would recommend using RestKit, it has a request queue that checks the network status on the device and starts uploading once network access has been assured. You can read more about this here: http://mobile.tutsplus.com/tutorials/iphone/advanced-restkit-development_iphone-sdk/. Read the sections about Request Queue and background download/upload. It should be noted that RestKit is a big library which has it's advantages and disadvantages. I'm not completely sure how this que works with the app lifecycle, if it saves the request que even if the app is terminated. You would have to investigate that. RestKit does support background uploading/downloading, but as already noted, I think it's impossible to do any uploading if the app is terminated and not in background state.
I wouldn't recommend using RestKit if the API isn't Rest though.
You can download and experiment with RestKit here: https://github.com/RestKit/RestKit.

Resources