当应用程序在 iOS12 中进入后台时,URLSessionDelegate 的 didWriteData 不会调用

Posted

技术标签:

【中文标题】当应用程序在 iOS12 中进入后台时,URLSessionDelegate 的 didWriteData 不会调用【英文标题】:URLSessionDelegate's didWriteData not call when app is going to background in iOS12 【发布时间】:2018-11-23 09:14:19 【问题描述】:

我想实现下载功能,可以用百分比显示下载任务的完成状态。我能够做到这一点,但问题是当应用程序移动到后台并回到前台时,ios12 中没有调用委托方法didWriteData。谁能帮帮我吗?这是我的代码

protocol DownloadDelagate 
    func downloadingProgress(value:Float)
    func downloadCompleted(identifier: Int,url: URL)


class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate 

    static var shared = DownloadManager()
    var delegate: DownloadDelagate?
    var backgroundSessionCompletionHandler: (() -> Void)?

    var session : URLSession 
        get 

            let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")
            config.isDiscretionary = true
            config.sessionSendsLaunchEvents = true
            return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
        
    

    private override init() 
    

    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) 
        DispatchQueue.main.async 
            if let completionHandler = self.backgroundSessionCompletionHandler 
                self.backgroundSessionCompletionHandler = nil
                completionHandler()
            
        
    

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) 
        delegate?.downloadCompleted(identifier: downloadTask.taskIdentifier, url: location)
    

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) 
        if totalBytesExpectedToWrite > 0 
            let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
            let progressPercentage = progress * 100
            delegate?.downloadingProgress(value: progressPercentage)
            print("Download with task identifier: \(downloadTask.taskIdentifier) is \(progressPercentage)% complete...")
        
    

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 
        if let error = error 
            print("Task failed with error: \(error)")
         else 
            print("Task completed successfully.")
        
    

【问题讨论】:

获取一个代表您的 DownloadManger 的对象。在该对象类中添加deinit print("class deinited") 。现在,当您进入后台时,请检查您的委托对象是否还活着。如果它被取消初始化,您将看到打印的语句。这基本上意味着你的弱引用被释放并且你的函数没有被触发,因为它没有委托。 你是在告诉func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)这个方法didWriteData吗? @Vicky_Vignesh 是的,这个方法。 【参考方案1】:

基于this thread,这是NSURLSesstion 中的一个错误。目前有已知的解决方法(经 Apple 工程师批准):

var session: URLSession?
...
func applicationDidBecomeActive(_ application: UIApplication) 
    session?.getAllTasks  tasks in
        tasks.first?.resume() // It is enough to call resume() on only one task
        // If it didn't work, you can try to resume all
        // tasks.forEach  $0.resume() 
    

【讨论】:

【参考方案2】:

请在 AppDelegate 的 applicationWillEnterForeground() 中尝试您的代码。当应用程序从背景转换到活动状态时,您可以在此处进行更改。

【讨论】:

以上是关于当应用程序在 iOS12 中进入后台时,URLSessionDelegate 的 didWriteData 不会调用的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序在 Tinder/Scarlet Websocket 中进入后台时保持 websocket 打开

当 FragmentActivity 在 Android 中进入后台时出现 NotSerializableException

自调整大小的集合视图在 iOS 15 中进入递归循环

仅当应用程序在后台请求位置后进入前台时才调用 didUpdateLocations

跟踪 iOS 应用程序在后台运行的时间

在 Android Pie (API-28) 中进入活动时键盘不显示