-
本文主要想解决的问题是,当你在前台点击上传文件,当用户进入到后台时你仍然想继续将文件上传完,而不是中断文件上传。如果你是打算直接在后台创建任务,那么会有延时的问题,当任务非常多的时候,靠后的任务延时将会非常严重(参考文章),因此这种情况也不在本文考虑范围内。
-
后台上传需要创建后台session,需要通过一个标识符Identifier,如果你每次只需要上传一个文件,那么你可以创建一个全局的session,所有的文件都可以通过该session创建task上传,文件依次上传即可。如果你需要每次同时上传多个文件,那么可以根据你的需要创建多个session,但是session的Identifier必须不一样,否则运行过程当中会出错。以下代码可创建多个session
//MARK: - 创建后台请求session func creatBackgroundSession(){ let nowDate = Date() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "YYYYMMddHHMMSS" let dateStr = dateFormatter.string(from: nowDate) let randomNum = Int(arc4random()%10000)+1 let configrationIdentifier = "test" + dateStr + String(randomNum) let backgroundSessionConfigration = URLSessionConfiguration.background(withIdentifier: configrationIdentifier) //设置后台上传时的超时timeoutIntervalForResource,默认值为1周 backgroundSessionConfigration.timeoutIntervalForResource = 24*60*60 backgroundSession = URLSession(configuration: backgroundSessionConfigration, delegate: self, delegateQueue: OperationQueue.main) }
-
创建上传的task,urlsession后台上传一定是文件流的形式,而不是数据流的形式,因此除了前端需要注意还应当与后台进行沟通,让他们以接受文件流的形式存储收到的流。
var request = URLRequest(url: URL(string: url )!) request.httpMethod = "POST" let contentType = "multipart/form-data; boundary=\(XYboundary)" request.setValue(contentType, forHTTPHeaderField: "Content-Type") request.addValue("text/html,application/json,text/json", forHTTPHeaderField: "Accept") //创建上传的 let backgroundTask = backgroundSession.uploadTask(with: request, fromFile: URL(fileURLWithPath: filePath)) // 开始下载 backgroundTask.resume()
-
需要实现URLSessionDelegate,URLSessionTaskDelegate,URLSessionDataDelegate等代理方法
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { //对进度进行监控 } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { //用来接收上传完成后后台返回的数据 } //MARK: - 上传结束操作,不管是否成功都会调用 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { //用来处理上传结束流程 } //MARK: - 后台上传完执行代理方法 func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { //如果是在后台上传的还会调用这个方法 }
-
当然,在AppDelegate中你还得实现如下方法
//MARK: - 后台下载上传完成处理 func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { }
-
如果你想停止上传,那么可以通过如下两种方式结束这个session
-
backgroundSession.finishTasksAndInvalidate()
,这个方法会在完成已开启的task后,结束这个session -
backgroundSession.invalidateAndCancel()
,该方法是立即停止task并结束session
-
-
这里有一个完整的Demo,参考Demo相信你可以加深理解,如果对你有帮助,给个Star,让更多人可以得到帮助。Demo在这里
-
本文谢绝转载,如需转载请联系我授权,原创不易,还请理解
网友评论