Resumable File Transfers with URLSession in Swift

abdul ahad
3 min read1 day ago

--

Photo by Rocker Sta on Unsplash

Large file uploads and downloads can be an integral part of modern applications, yet we often suffer from interruptions due to network issues. To provide a seamless user experience, implementing resumable file transfers in iOS apps could be essential. Apple’s URLSession provides powerful tools for handling these scenarios efficiently.

This article explores how to implement robust and resumable file transfers using URLSession in Swift, ensuring large uploads and downloads remain fault-tolerant and efficient.

Why Resumable Transfers Matter

When dealing with large files, any network interruption — such as Wi-Fi disconnection or app suspension — forces a restart without resumable protocols. This leads to:

  • Wasted time restarting from the beginning.
  • High bandwidth usage and unnecessary data consumption.
  • Poor user experience due to failed downloads or uploads.

By leveraging modern HTTP protocols, apps can resume transfers instead of starting over, optimizing bandwidth and improving reliability.

Resumable Downloads with URLSession

How Do Resumable Downloads Work?

Initial Request:

  • The app sends an HTTP GET request to fetch a file.
  • The server responds with the file and includes two important headers:
  • Accept-Ranges: bytes → Indicates support for resumable downloads.
  • ETag → A unique identifier for the file.

Handling Interruptions:

  • If the connection is lost, the partially downloaded file is saved.
  • The app sends another request with:
  • Range: bytes=x- → Requests only the missing part.
  • If-Range: <ETag> → Ensures the file hasn't changed.

Resuming the Download:

  • If the file is unchanged, the server responds with:
  • 206 Partial Content → Sends only the missing bytes.
  • The app appends this data to the saved file, completing the download.

Using URLSession for Resumable Downloads

Start a Download

let urlSession = URLSession(configuration: .default)
let task = urlSession.downloadTask(with: url)
task.resume()

Pause a Download Manually

task.cancel(byProducingResumeData: { resumeData in
// Store resumeData for later use
})

Resume a Paused Download

let newTask = urlSession.downloadTask(withResumeData: resumeData)
newTask.resume()

Handle Network Failures

if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
let newTask = urlSession.downloadTask(withResumeData: resumeData)
newTask.resume()
}

Requirements for Resumable Downloads

  • The server must support range requests (Accept-Ranges: bytes).
  • The server must provide an ETag or Last-Modified header.
  • The download must be an HTTP GET request.
  • The temporary download file must not be deleted due to system pressure.

Resumable Uploads in iOS 17

Why Are Resumable Uploads Important?

  • Upload speeds are generally slower than downloads.
  • Restarting an upload due to a minor interruption wastes time and data.
  • iOS 17 introduces resumable upload tasks in URLSession.

How Resumable Uploads Work

  1. Starting an Upload Task
  2. Pausing the Upload using cancelByProducingResumeData
  3. Resuming with uploadTask(withResumeData:)
  4. Handling Interruptions: iOS automatically retries if the server supports resumable uploads.

Server Requirements for Resumable Uploads

  1. The server must support the resumable upload protocol (under standardization by IETF).
  2. The client sends a request with:Upload-Incomplete: ?0 → Indicates support for resumable uploads.
  3. If supported, the server responds with 104 Informational Response → Provides a resume URL.
  4. In case of an interruption:
  • The client sends a HEAD request to check how much data was received.
  • The server responds with the upload offset (bytes uploaded so far).
  • The client resumes from that offset.

Background URLSession for Large Transfers

Why Use Background URLSession?

  • Transfers continue even if the app is closed or suspended.
  • The system waits for internet connectivity before retrying failed tasks.
  • iOS automatically reschedules uploads in a power-efficient way.

How to Use Background URLSession

Create a Background Session

let config = URLSessionConfiguration.background(withIdentifier: "com.app.uploads")
let backgroundSession = URLSession(configuration: config)

Use Background Session for Large Uploads/Downloads

let task = backgroundSession.downloadTask(with: url)
task.resume()

Monitor Progress in the Background

func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL) {
// Handle completed download
}

Optimizing Background Transfers

  • Set isDiscretionary = true → Lets iOS schedule when optimal.
  • Use allowsConstrainedNetworkAccess = false → Avoids Low Data Mode usage.
  • Set countOfBytesClientExpectsToSend/Receive → Helps iOS allocate resources efficiently.

Conclusion

  1. Resumable transfers improve user experience by preventing restarts due to network issues.

2. Use URLSession for handling resumable downloads and uploads:

  • Downloads: Use cancelByProducingResumeData and downloadTask(withResumeData:).
  • Uploads: Utilize the new resumable upload APIs in iOS 17.

3. Ensure server support for resumable uploads (consider SwiftNIO for server-side implementation).

By implementing these techniques, your app’s networking capabilities will become more reliable, efficient, and user-friendly.

Reference:

--

--

abdul ahad
abdul ahad

Written by abdul ahad

A software developer dreaming to reach the top and also passionate about sports and language learning

No responses yet