Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: Perform upload task while app is in background

Is there really no way to run an UPLOAD task while an iOS app is in the background? This is ridiculous. Been looking at various stuff like NSURLSessionUploadTask, dispatch_after and even NSTimer, but nothing works for more than the meager 10 seconds the app lives after being put in the background.

How do other apps that have uploads work? Say, uploading an image to Facebook and putting the app in the background, will that cancel the upload?

Why cannot iOS have background services or agents like Android and Windows Phone has?

This is a critical feature of my app, and on the other platforms is works perfectly.

Any help is appreciated :(

like image 561
Christoffer Avatar asked May 23 '14 12:05

Christoffer


1 Answers

You can continue uploads in the background with a “background session”. The basic process of creating a background URLSessionConfiguration with background(withIdentifier:) is outlined in Downloading Files in the Background. That document focuses on downloads, but the same basic process works for upload tasks, too.

Note:

  • you have to use the delegate-based URLSession;

  • you cannot use the completion handler renditions of the task factory methods with background sessions;

  • you also have to use uploadTask(with:fromFile:) method, not the Data rendition ... if you attempt to use uploadTask(with:from:), which uses Data for the payload, with background URLSession you will receive exception with a message that says, “Upload tasks from NSData are not supported in background sessions”; and

  • your app delegate must implement application(_:handleEventsForBackgroundURLSession:completionHandler:) and capture that completion handler which you can then call in your URLSessionDelegate method urlSessionDidFinishEvents(forBackgroundURLSession:) (or whenever you are done processing the response).


By the way, if you don't want to use background NSURLSession, but you want to continue running a finite-length task for more than a few seconds after the app leaves background, you can request more time with UIApplication method beginBackgroundTask. That will give you a little time (formerly 3 minutes, only 30 seconds in iOS 13 and later) complete any tasks you are working on even if the user leave the app.

See Extending Your App's Background Execution Time. Their code snippet is a bit out of date, but a contemporary rendition might look like:

func initiateBackgroundRequest(with data: Data) {
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

    // Request the task assertion and save the ID.
    backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Finish Network Tasks") {
        // End the task if time expires.
        if backgroundTaskID != .invalid {
            UIApplication.shared.endBackgroundTask(backgroundTaskID)
            backgroundTaskID = .invalid
        }
    }

    // Send the data asynchronously.
    performNetworkRequest(with: data) { result in
        // End the task assertion.
        if backgroundTaskID != .invalid {
            UIApplication.shared.endBackgroundTask(backgroundTaskID)
            backgroundTaskID = .invalid
        }
    }
}

Please don’t get lost in the details here. Focus on the basic pattern:

  • begin the background task;
  • supply a timeout clause that cleans up the background task if you happen to run out of time;
  • initiate whatever you need to continue even if the user leaves the app; and
  • in the completion handler of the network request, end the background task.
like image 161
Rob Avatar answered Sep 18 '22 07:09

Rob