Ios 后台上传在Swift中不起作用
我正在尝试实现一个代码,其中一个API将在文件上传到AWS服务器后不久调用,但它必须处于后台模式。虽然AWS sdk在后台模式下管理将文件上载到其服务器,但以下代码不起作用 ViewController.swiftIos 后台上传在Swift中不起作用,ios,swift,urlsession,background-fetch,Ios,Swift,Urlsession,Background Fetch,我正在尝试实现一个代码,其中一个API将在文件上传到AWS服务器后不久调用,但它必须处于后台模式。虽然AWS sdk在后台模式下管理将文件上载到其服务器,但以下代码不起作用 ViewController.swift func upload(_ mediaData:Data){ //AWS method to upload a file AWSS3UploadImageData(mediaData!, strImageName: "person.jpg", strContentTyp
func upload(_ mediaData:Data){
//AWS method to upload a file
AWSS3UploadImageData(mediaData!, strImageName: "person.jpg", strContentType: "img/*", { (isSuccess, result, strMessage) in
if isSuccess {
let arrPost = result as! [[String : String]]
//Call custom webservice
VaultUploadWebService.shared.callVaultUploadWebService(Params: arrPost)
}
else {
print("Unsuccess")
}
})
}
class VaultUploadWebService: NSObject {
static let shared = VaultUploadWebService()
var savedCompletionHandler: (() -> Void)?
func callVaultUploadWebService(Params: [[String : String]]) {
startRequest(for: "www.example.com", param: Params)
}
func startRequest (for urlString: String, param: [[String : String]]) {
let identifier = "com.com.background" + "\(NSDate().timeIntervalSince1970 * 1000)"
let configuration = URLSessionConfiguration.background(withIdentifier:identifier)
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let url = URL(string: urlString)!
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 180)
request.httpMethod = "post"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let paramsData = try JSONSerialization.data(withJSONObject:param, options:[])
request.httpBody = paramsData
session.uploadTask(withStreamedRequest: request).resume()
}catch {
print("JSON serialization failed: ", error)
return
}
//Also tried using the following but no luck
/*guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileUrl = documentDirectoryUrl.appendingPathComponent("Persons.json")
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(param)
try jsonData.write(to: fileUrl, options: [])
}
catch let error {
print(error.localizedDescription)
}
session.uploadTask(with: request, fromFile: fileUrl).resume()*/
}
}
extension VaultUploadWebService: URLSessionDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
self.savedCompletionHandler?()
self.savedCompletionHandler = nil
}
}
}
extension VaultUploadWebService: URLSessionTaskDelegate{
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if (error != nil){
print(error?.localizedDescription ?? "error")
}
else{
print(task.response)
}
}
}
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
let id = identifier as NSString
if id.contains("com.amazonaws") {
AWSS3TransferUtility.interceptApplication(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler)
}else{
VaultUploadWebService.shared.savedCompletionHandler = completionHandler
}
}
VaultWebService.swift
func upload(_ mediaData:Data){
//AWS method to upload a file
AWSS3UploadImageData(mediaData!, strImageName: "person.jpg", strContentType: "img/*", { (isSuccess, result, strMessage) in
if isSuccess {
let arrPost = result as! [[String : String]]
//Call custom webservice
VaultUploadWebService.shared.callVaultUploadWebService(Params: arrPost)
}
else {
print("Unsuccess")
}
})
}
class VaultUploadWebService: NSObject {
static let shared = VaultUploadWebService()
var savedCompletionHandler: (() -> Void)?
func callVaultUploadWebService(Params: [[String : String]]) {
startRequest(for: "www.example.com", param: Params)
}
func startRequest (for urlString: String, param: [[String : String]]) {
let identifier = "com.com.background" + "\(NSDate().timeIntervalSince1970 * 1000)"
let configuration = URLSessionConfiguration.background(withIdentifier:identifier)
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let url = URL(string: urlString)!
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 180)
request.httpMethod = "post"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let paramsData = try JSONSerialization.data(withJSONObject:param, options:[])
request.httpBody = paramsData
session.uploadTask(withStreamedRequest: request).resume()
}catch {
print("JSON serialization failed: ", error)
return
}
//Also tried using the following but no luck
/*guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileUrl = documentDirectoryUrl.appendingPathComponent("Persons.json")
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(param)
try jsonData.write(to: fileUrl, options: [])
}
catch let error {
print(error.localizedDescription)
}
session.uploadTask(with: request, fromFile: fileUrl).resume()*/
}
}
extension VaultUploadWebService: URLSessionDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
self.savedCompletionHandler?()
self.savedCompletionHandler = nil
}
}
}
extension VaultUploadWebService: URLSessionTaskDelegate{
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if (error != nil){
print(error?.localizedDescription ?? "error")
}
else{
print(task.response)
}
}
}
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
let id = identifier as NSString
if id.contains("com.amazonaws") {
AWSS3TransferUtility.interceptApplication(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler)
}else{
VaultUploadWebService.shared.savedCompletionHandler = completionHandler
}
}
最后Appdelegate.swift
func upload(_ mediaData:Data){
//AWS method to upload a file
AWSS3UploadImageData(mediaData!, strImageName: "person.jpg", strContentType: "img/*", { (isSuccess, result, strMessage) in
if isSuccess {
let arrPost = result as! [[String : String]]
//Call custom webservice
VaultUploadWebService.shared.callVaultUploadWebService(Params: arrPost)
}
else {
print("Unsuccess")
}
})
}
class VaultUploadWebService: NSObject {
static let shared = VaultUploadWebService()
var savedCompletionHandler: (() -> Void)?
func callVaultUploadWebService(Params: [[String : String]]) {
startRequest(for: "www.example.com", param: Params)
}
func startRequest (for urlString: String, param: [[String : String]]) {
let identifier = "com.com.background" + "\(NSDate().timeIntervalSince1970 * 1000)"
let configuration = URLSessionConfiguration.background(withIdentifier:identifier)
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let url = URL(string: urlString)!
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 180)
request.httpMethod = "post"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let paramsData = try JSONSerialization.data(withJSONObject:param, options:[])
request.httpBody = paramsData
session.uploadTask(withStreamedRequest: request).resume()
}catch {
print("JSON serialization failed: ", error)
return
}
//Also tried using the following but no luck
/*guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileUrl = documentDirectoryUrl.appendingPathComponent("Persons.json")
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(param)
try jsonData.write(to: fileUrl, options: [])
}
catch let error {
print(error.localizedDescription)
}
session.uploadTask(with: request, fromFile: fileUrl).resume()*/
}
}
extension VaultUploadWebService: URLSessionDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
self.savedCompletionHandler?()
self.savedCompletionHandler = nil
}
}
}
extension VaultUploadWebService: URLSessionTaskDelegate{
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if (error != nil){
print(error?.localizedDescription ?? "error")
}
else{
print(task.response)
}
}
}
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
let id = identifier as NSString
if id.contains("com.amazonaws") {
AWSS3TransferUtility.interceptApplication(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler)
}else{
VaultUploadWebService.shared.savedCompletionHandler = completionHandler
}
}
但是这个委托方法从未被调用,而它是为AWS上传而被调用的。我认为这是后台
上传任务不适合我的主要原因。卡了两天。任何帮助都将不胜感激。后台下载事件不会在模拟器上触发。您只能在真实设备上进行测试。httpBody
如果您通过uploadTask(with streamedrequest:)
创建上载任务,则忽略该操作。它需要实现urlSession(uquot:task:needNewBodyStream:)
委托回调。对于背景模式,它不适合。尝试使用uploadTask(带request:URLRequest,来自bodyData:Data)
。另外,看起来VaultUploadWebService
没有对会话
对象的任何引用。尝试将会话
存储为Vault UploadWebService
的成员uploadTask(with streamedRequest:…)
与后台URL会话不兼容。改用uploadTask(with:request,fromFile:…)
。可能是UIBackgroundTaskIdentifier可以帮助您,请阅读相关内容。您是否在功能中启用了后台模式?@TarasChernyshenko:Yes是否检查您试图在后台命中的URL是否在方法startRequest中被命中,并且您是否得到任何响应?是否检查了此项?我试过了,运气不好。但有趣的是AWS iOS SDK的上传方法也可以在模拟器中运行。尝试了上传任务(使用request:URLRequest,from bodyData:Data)
…结果相同。您是否检查了至少一个请求已到达服务器?HTTP代理工具(例如Charles)可以帮助您实现这一点。换句话说,您的请求甚至没有被执行,或者您只是没有收到关于其执行状态的回调(成功或失败)?正如我在回答中指出的,会话
对象可能在执行startRequest
方法结束时被释放,因为VaultUploadWebService
没有对它的任何引用。检查这一点,因为它也可能导致此问题。是的,因为调用了func-urlSession(u-session:urlSession,task:URLSessionTask,didCompleteWither错误:error?)
。我正在检查session
是否在startRequest执行结束时解除分配