2023 System Services
WWDC23 · 21 min · System Services
Build robust and resumable file transfers
Find out how URLSession can help your apps transfer large files and recover from network interruptions. Learn how to pause and resume HTTP file transfers and support resumable uploads, and explore best practices for using URLSession to transfer files even when your app is suspended in the background.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 12 snippets
Pausing and resuming a URLSessionDownloadTask
let downloadTask = session.downloadTask(with: request)
downloadTask.resume() Pausing and resuming a URLSessionDownloadTask
let downloadTask = session.downloadTask(with: request)
downloadTask.resume()
guard let resumeData = await downloadTask.cancelByProducingResumeData() else {
// Download cannot be resumed
return
} Pausing and resuming a URLSessionDownloadTask
let downloadTask = session.downloadTask(with: request)
downloadTask.resume()
guard let resumeData = await downloadTask.cancelByProducingResumeData() else {
// Download cannot be resumed
return
}
let newDownloadTask = session.downloadTask(withResumeData: resumeData)
newDownloadTask.resume() Retrieving resume data on error
do {
let (url, response) = try await session.download(for: request)
} catch let error as URLError {
guard let resumeData = error.downloadTaskResumeData else {
// Download cannot be resumed
return
}
} Pausing and resuming a URLSessionUploadTask
let uploadTask = session.uploadTask(with: request, fromFile: fileURL)
uploadTask.resume() Pausing and resuming a URLSessionUploadTask
let uploadTask = session.uploadTask(with: request, fromFile: fileURL)
uploadTask.resume()
guard let resumeData = await uploadTask.cancelByProducingResumeData() else {
// Upload cannot be resumed
return
} Pausing and resuming a URLSessionUploadTask
let uploadTask = session.uploadTask(with: request, fromFile: fileURL)
uploadTask.resume()
guard let resumeData = await uploadTask.cancelByProducingResumeData() else {
// Upload cannot be resumed
return
}
let newUploadTask = session.uploadTask(withResumeData: resumeData)
newUploadTask.resume() Retrieving resume data on error
do {
let (data, response) = try await session.upload(for: request, fromFile: fileURL)
} catch let error as URLError {
guard let resumeData = error.uploadTaskResumeData else {
// Upload cannot be resumed
return
}
} Before resumable uploads in Swift NIO
NIOTSListenerBootstrap(group: NIOTSEventLoopGroup())
.childChannelInitializer { channel in
channel.configureHTTP2Pipeline(mode: .server) { channel in
channel.pipeline.addHandlers([
HTTP2FramePayloadToHTTPServerCodec(),
ExampleChannelHandler()
])
}.map { _ in () }
}
.tlsOptions(tlsOptions) Add resumable uploads in Swift NIO
import NIOResumableUpload
let uploadContext = HTTPResumableUploadContext(origin: "https://example.com")
NIOTSListenerBootstrap(group: NIOTSEventLoopGroup())
.childChannelInitializer { channel in
channel.configureHTTP2Pipeline(mode: .server) { channel in
channel.pipeline.addHandlers([
HTTP2FramePayloadToHTTPServerCodec(),
HTTPResumableUploadHandler(context: uploadContext, handlers: [
ExampleChannelHandler()
])
])
}.map { _ in () }
}
.tlsOptions(tlsOptions) Informational responses in URLSession
protocol URLSessionTaskDelegate : URLSessionDelegate {
optional func urlSession(_ session: URLSession, task: URLSessionTask,
didReceiveInformationalResponse response: HTTPURLResponse)
} Using background URLSession
// Configuring your background session
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app")
configuration.isDiscretionary = true
configuration.allowsConstrainedNetworkAccess = false
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
// Configuring your background task
let backgroundTask = session.uploadTask(with: url, fromFile: fileURL)
backgroundTask.earliestBeginDate = .now.addingTimeInterval(60 * 60)
backgroundTask.countOfBytesClientExpectsToSend = 500 * 1024
backgroundTask.countOfBytesClientExpectsToReceive = 200 Resources
Related sessions
-
57 min