[英]Swift: Background upload using URLSession
I'm trying to upload files to the s3 bucket using URLSession.我正在尝试使用 URLSession 将文件上传到 s3 存储桶。 I understood that to upload files in the background, I need to use uploadTask(with:fromFile:)
method as mentioned here .我知道要在后台上传文件,我需要使用这里提到的uploadTask(with:fromFile:)
方法。 So I am performing below steps to upload the file.所以我正在执行以下步骤来上传文件。
lazy var session: URLSession = {
let bundleIdentifier = Bundle.main.bundleIdentifier!
let config = URLSessionConfiguration.background(withIdentifier: bundleIdentifier + ".background")
config.sharedContainerIdentifier = bundleIdentifier
config.sessionSendsLaunchEvents = true
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
Data Model数据 Model
struct UploadRequest {
let destinationUrl: URL
let sourceURL: URL
let params: [String: String]
let fileName: String
let mimeType: String
}
private func requestAndPath(for
uploadParam: UploadRequest) -> (request: URLRequest,
filePath: URL)? {
// Create an empty file and append header, file content and footer to it
let uuid = UUID().uuidString
let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
let fileURL = directoryURL.appendingPathComponent(uuid)
let filePath = fileURL.path
FileManager.default.createFile(atPath: filePath, contents: nil, attributes: nil)
let file = FileHandle(forWritingAtPath: filePath)!
let boundary = UUID().uuidString
let newline = "\r\n"
do {
let partName = "file"
let data = try Data(contentsOf: uploadParam.sourceURL)
// Write boundary header
var header = ""
header += "--\(boundary)" + newline
header += "Content-Disposition: form-data; name=\"\(partName)\"; filename=\"\(uploadParam.fileName)\"" + newline
for (key, value) in uploadParam.params {
header += "Content-Disposition: form-data; name=\"\(key)" + newline
header += newline
header += value + newline
}
header += "Content-Type: \(uploadParam.mimeType)" + newline
header += newline
let headerData = header.data(using: .utf8, allowLossyConversion: false)
// Write data
file.write(headerData!)
file.write(data)
// Write boundary footer
var footer = ""
footer += newline
footer += "--\(boundary)--" + newline
footer += newline
let footerData = footer.data(using: .utf8, allowLossyConversion: false)
file.write(footerData!)
file.closeFile()
let contentType = "multipart/form-data; boundary=\(boundary)"
var urlRequest = URLRequest(url: uploadParam.destinationUrl)
urlRequest.httpMethod = "POST"
urlRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
return (urlRequest, fileURL)
} catch {
debugPrint("Error generating url request")
}
return nil
}
func uploadFile(request: UploadRequest) {
if let reqPath = requestAndPath(for: uploadRequest) {
let task = session.uploadTask(with: reqPath.request,
fromFile: reqPath.filePath)
task.resume()
}
}
When I call the uploadFile
method, the delegate didSendBodyData
is called once and the control goes to didCompleteWithError
with error as nil.当我调用uploadFile
方法时,委托didSendBodyData
被调用一次,并且控件转到didCompleteWithError
,错误为nil。 But the file is not uploaded to the s3 bucket.但是文件没有上传到 s3 存储桶。 What could be the issue?可能是什么问题?
I am able to upload the file using Alamofire but since Alamofire doesn't support background upload , I would like to fallback to URLSession我可以使用 Alamofire 上传文件,但由于 Alamofire 不支持后台上传,我想回退到 URLSession
Upload using Alamofire (default)使用 Alamofire 上传(默认)
AF.upload(multipartFormData: { multipartFormData in
for (key, value) in uploadRequest.params {
if let data = value.data(using: String.Encoding.utf8, allowLossyConversion: false) {
multipartFormData.append(data, withName: key)
}
}
multipartFormData.append(
uploadRequest.sourceURL,
withName: "File",
fileName: uploadRequest.fileName,
mimeType: uploadRequest.mimeType
)
}, with: urlRequest).responseData { response in
if let responseData = response.data {
let strData = String(decoding: responseData, as: UTF8.self)
debugPrint("Response data \(strData)")
} else {
debugPrint("Error is \(response.error)")
}
}.uploadProgress { progress in
debugPrint("Progress \(progress)")
}
I made changes in the request body and wrote the data to the file and used uploadTask(with:fromFile:)
method using the background session.我在请求正文中进行了更改并将数据写入文件并使用后台 session 的uploadTask(with:fromFile:)
方法。 urlSessionDidFinishEvents(forBackgroundURLSession:)
will be called once the upload is completed when the app is in the background. urlSessionDidFinishEvents(forBackgroundURLSession:)
将在应用处于后台时在上传完成后调用。
private func requestAndPath(for
uploadParam: UploadRequest) -> (request: URLRequest,
filePath: URL)? {
let uuid = UUID().uuidString
let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
let fileURL = directoryURL.appendingPathComponent(uuid)
let filePath = fileURL.path
FileManager.default.createFile(atPath: filePath, contents: nil, attributes: nil)
let file = FileHandle(forWritingAtPath: filePath)!
let boundary = generateBoundary()
let lineBreak = "\r\n"
var body = Data()
for (key, value) in uploadParam.params {
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"\(key)\"\(lineBreak + lineBreak)")
body.append("\(value + lineBreak)")
}
do {
let data = try Data(contentsOf: uploadParam.sourceURL)
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"File\"; filename=\"\(uploadParam.fileName)\"\(lineBreak)")
body.append("Content-Type: \(uploadParam.mimeType + lineBreak + lineBreak)")
body.append(data)
body.append(lineBreak)
body.append("--\(boundary)--\(lineBreak)")
file.write(body)
file.closeFile()
var urlRequest = URLRequest(url: uploadParam.destinationUrl)
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = "POST"
return (urlRequest, fileURL)
} catch {
debugPrint("Error getting request")
}
return nil
}
func generateBoundary() -> String {
return UUID().uuidString
}
extension Data {
mutating func append(_ string: String) {
if let data = string.data(using: .utf8) {
self.append(data)
}
}
}
Reference: https://stackoverflow.com/a/58246456/696465参考: https://stackoverflow.com/a/58246456/696465
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.