Ios 当应用程序位于后台时,使用URLSession和操作队列下载不会启动下一个操作

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

用例:通过一个API从服务器下载文件,该API将给出下载服务器url(下载服务器url有效期仅为10秒)

我已经启用了后台功能。 然后创建了一个下载管理器,用于保存下载数据任务的操作队列。 在Operation类when main()函数调用时,我进行了API调用,该调用将返回下载服务器URL并开始下载

在调试模式下工作正常,但在发布模式下不工作

下载管理器:

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的解决方案?