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.
Related
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.
I've spent a lot of time looking at the options but am still not 100% clear, so wanted to reach out for some guidance.
Scenario is this:
User submits an HTTPS request to our backend server for some data via an iOS app
Depending on the data, the first (only) request can take a REALLY long time. like, say, 10+ minutes (shocking i know)
When that payload finally does become available and is returned via the HTTPS request, we then want to use it to update the UI in background.
The assumption here is that the user has moved on to another app whilst waiting for the data to arrive (and lets also assume they haven't killed the app).
Is it possible to handle this via iOS 8+ API's without the app being force/killed by Apple when in the background ?
Could we use background task for example?
var backgroundTask: UIBackgroundTaskIdentifier
xxx.beginBackgroundTaskWithName...
etc
Before testing some code blocks we just wanted to see if someone has (a) already done this and/or (b) whether we're heading in the right direction
Thanks for your help.
You should re-think on your web service which may take almost 10 min to process. If you are not able to optimize server task processing time then below one of the idea may be help you.
You can divided your one request into multiple request to reduce processing time and get response in faster way.
Your server should sent notification to app when its done with its task. So app will came to know task is done.
I am not sure why you try to update UI when apps in background mode , you may try to update UI when users come to foreground mode from background mode.
Please check this link which show as example of long running task. Where its use a blank audio play to keep alive app background task.
You can used "Background fetch" functionality.
For learning purpose you can refer this link
I have an iOS app that needs to sync a lot of data from the cloud to device when first installed, maybe even 2GB worth if the user wants access to everything offline. Without saying "change your design", how can I ensure this initial sync completes without too much interaction from the user?
Currently it will complete as long as they keep my app in the foreground and don't let the device go to sleep. I'd like to allow them to use other apps or let the screen turn off during this process, since it's a pretty boring thing to watch.
I've seen application:performFetchWithCompletionHandler: and
beginBackgroundTaskWithName:expirationHandler, but they only allow for a short amount of time (around 30 seconds) to complete a task. Is there something better, or do I need to complicate my design by stopping my sync every ~25 seconds, and then resume next time I'm given more time by the OS?
My app is like Microsoft Outlook, it has emails (in some case millions), contacts, calendar, and several other areas. I have different sync options to limit the amount of data, but some users want access to everything offline (yes, even emails and attachments that are 10 years old). I think they are silly, but can't argue with the end-users.
I know this is a really old question, but I suggest you use NSURLSession to download data in the background even without your app running.
You simply create an NSURLSession that uses a Background NSURLSessionConfiguration (use NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier:) and create an NSURLSessionDownloadTask for each request you need to download.
NSURLSession will download the data even when your app is not running at all, and it will save the data as files in your app's sandbox. Implement the NSURLSession delegate methods to receive notification of the download completion, read the downloaded files and save them how you see fit.
You should check out Apple's guide on Using NSURLSession.
I have an app that send 300+ files across the network, normally we request an additional 10 minutes timer when the app moves to the background in case we need to send, but after 10 minutes the app is moved to the suspended state.
Can NSUrlConnection prevent this suspension and continue download from the background>
you get only 3 minutes in iOS 7, not 10 as before.
NSURLConnection cannot help you there.
NSURLSession has a facility for uploading files in the background, outside of that time. However, it doesn't keep a continuous task running like UIBackgroundTaskIdentifier-based methods, and you must use on-device files as the basis of the upload. I found it to take a lot of work to get it right, so be prepared. I'd start with a thorough review of Apple's URL Loading System Programming Guide, which isn't really well written, but is entirely necessary.
I would like to add Flurry to an iPad app that is meant to stay running in the foreground for several weeks.
Flurry apparently only uploads information to its servers on events such as app start, app close, app pause, but I don't expect my app to enter those states very often. I need app feedback sooner.
Is it possible to force Flurry to send data on a timer, say every hour or two?
I found a way that seems to work. To test, I created an NSTimer that calls [FlurryAPI startSession:#"yourKeyHere"] every five minutes, then let my program run without stopping or pausing it in any way, and the event data is appearing on the Flurry server.
The comments above that method in the .h file do say "start session, attempt to send saved sessions to server", so in a sense it's documented, but it feels like a hack to have to call something called startSession more than once per application run. This is partly why I'm switching to MixPanel, which has a documented upload interval feature.