Ios 当应用程序位于后台时,使用URLSession和操作队列下载不会启动下一个操作
用例:通过一个API从服务器下载文件,该API将给出下载服务器url(下载服务器url有效期仅为10秒) 我已经启用了后台功能。 然后创建了一个下载管理器,用于保存下载数据任务的操作队列。 在Operation类when main()函数调用时,我进行了API调用,该调用将返回下载服务器URL并开始下载 在调试模式下工作正常,但在发布模式下不工作 下载管理器:Ios 当应用程序位于后台时,使用URLSession和操作队列下载不会启动下一个操作,ios,swift,nsurlsession,nsoperationqueue,nsoperation,Ios,Swift,Nsurlsession,Nsoperationqueue,Nsoperation,用例:通过一个API从服务器下载文件,该API将给出下载服务器url(下载服务器url有效期仅为10秒) 我已经启用了后台功能。 然后创建了一个下载管理器,用于保存下载数据任务的操作队列。 在Operation类when main()函数调用时,我进行了API调用,该调用将返回下载服务器URL并开始下载 在调试模式下工作正常,但在发布模式下不工作 下载管理器: final class SCDownloadManager: NSObject { @objc static var shar
final class SCDownloadManager: NSObject {
@objc static var shared = SCDownloadManager()
private override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(SCDownloadManager.networkDidChange(_:)), name: NSNotification.Name.init(NetworkConnectionChanged), object: nil)
}
/// Dictionary of operations, keyed by the `Download URL` of the `URLSessionTask`
fileprivate var operations = [URL: SCDownloadOperation]()
fileprivate var serverURLRequestMap = [URL: SCDownloadOperation]()
/// Serial NSOperationQueue for downloads
private let queue: OperationQueue = {
let _queue = OperationQueue()
_queue.name = "SCDownloadManagerQueue"
_queue.maxConcurrentOperationCount = 3
return _queue
}()
/// Delegate-based NSURLSession for DownloadManager
lazy var downloadSession: URLSession = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.xyz.background.download")
let sessionQueue = OperationQueue()
return URLSession(configuration: configuration, delegate: self, delegateQueue: sessionQueue)
}()
lazy var dataSession: URLSession = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.xyz.background.url")
let sessionQueue = OperationQueue()
return URLSession(configuration: configuration, delegate: self, delegateQueue: sessionQueue)
}()
@discardableResult
@objc func addDownload(_ downloadRecord: DownloadRecord) -> SCDownloadOperation {
let operation = SCDownloadOperation(withDownloadRecord: downloadRecord)
operation.delegate = self
operations[downloadRecord.downloadUrl] = operation
queue.addOperation(operation)
return operation
}
/// Cancel all queued operations
@objc func cancelAll() {
queue.cancelAllOperations()
}
@objc func networkDidChange(_ notification: Notification) {
if let reachability = notification.object as? Reachability {
if reachability.currentReachabilityStatus() == NotReachable {
cancelAll()
}
}
}
}
//MARK:- Download operation delegate
extension SCDownloadManager: SCDownloadOperationDelegate {
func getServerDownloadUrl(forRequest request: URLRequest, ofOperation operation: SCDownloadOperation) {
if let url = request.url {
serverURLRequestMap[url] = operation
}
self.dataSession.downloadTask(with: request).resume()
}
}
// MARK: URLSessionDownloadDelegate methods
extension SCDownloadManager: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
guard let sourceURL = downloadTask.originalRequest?.url else { return }
if session == dataSession {
if FileManager.default.isReadableFile(atPath: location.path) {
if let data = FileManager.default.contents(atPath: location.path) {
if let downloadOperation = serverURLRequestMap[sourceURL] {
if let serverUrl = String(data: data, encoding: .utf8), let downloadServerUrl = URL(string: serverUrl) {
self.operations.changeKey(from: downloadOperation.downloadRecord.downloadUrl, to: downloadServerUrl)
downloadOperation.downloadRecord.downloadUrl = downloadServerUrl
if let url = downloadOperation.downloadRecord.downloadUrl {
downloadOperation.downloadRecord.downloadTask = downloadSession.downloadTask(with: url)
downloadOperation.downloadRecord.downloadTask.resume()
}
}
}
do {
try FileManager.default.removeItem(at: location)
} catch {
print("error while removing file from default location")
}
}
}
} else {
operations[sourceURL]?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location)
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if session == self.downloadSession {
guard let sourceURL = downloadTask.originalRequest?.url else { return }
operations[sourceURL]?.urlSession(session, downloadTask: downloadTask, didWriteData: bytesWritten, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite)
}
}
}
// MARK: URLSessionTaskDelegate methods
extension SCDownloadManager: URLSessionTaskDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
if downloadSession == session {
DispatchQueue.main.async {
if let completionHandler = Constants.appDelegate.backgroundTransferCompletionHandler {
Constants.appDelegate.backgroundTransferCompletionHandler = nil
completionHandler()
}
}
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let sourceURL = task.originalRequest?.url else { return }
if session == dataSession {
if error == nil {
} else {
print("got error while doing API on download task")
}
} else {
operations[sourceURL]?.urlSession(session, task: task, didCompleteWithError: error)
operations.removeValue(forKey: sourceURL)
}
}
}
操作类:
class SCDownloadOperation: SCAsynchronousOperation {
let downloadRecord: DownloadRecord
var getServerDownloadUrl: ((URLRequest)->Void)?
weak var delegate: SCDownloadOperationDelegate?
init(withDownloadRecord dr: DownloadRecord) {
downloadRecord = dr
super.init()
}
override func cancel() {
if let task = downloadRecord.downloadTask{
task.cancel()
}
super.cancel()
}
override func main() {
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
let configuration = RequestConfiguration(withMethodType: .GET, urlString: downloadRecord.downloadUrl.absoluteString)
if let request = NetworkManager.sharedInstance.urlRequest(forRequestConfiguration: configuration) {
delegate?.getServerDownloadUrl(forRequest: request, ofOperation: self)
}
default: break
}
}
}
// MARK: NSURLSessionDownloadDelegate methods
extension SCDownloadOperation: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
downloadRecord.progress = 1
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
processDownloadFinish(atLocation: location)
default: break
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
downloadRecord.isExecuting = true
downloadRecord.isDownloadProgressAvailable = true
let downloadProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
downloadRecord.progress = downloadProgress
downloadRecord.percentComplete = ((Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))*100)
downloadRecord.downloadProgress = downloadProgress
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
updateWrittenData()
default: break
}
}
}
// MARK: NSURLSessionTaskDelegate methods
extension SCDownloadOperation: URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
completeOperation()
if error != nil {
print("\(String(describing: error))")
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
contentDownloadFail()
default: break
}
}
}
}
@Bhavesh:-将任务分配给BeginBackgroundTaskWithExpirationHandler我已经在didEnterInBackground中添加了代码。-(void)ApplicationIdentinterBackground:(UIApplication*)应用程序{块UIBackgroundTaskIdentifier backgroundTaskIdentifier=[[UIApplication sharedApplication]beginBackgroundTaskWithExpirationHandler:^{NSLog(@“后台时间:%f”,[[UIApplication sharedApplication]BackgroundTime剩余])[[UIApplication sharedApplication]endBackgroundTask:backgroundTaskIdentifier];backgroundTaskIdentifier=UIBackgroundTaskInvalid;}];}您有没有找到这个@BhaveshPatel的解决方案?