【问题标题】:How to handle background url session lost internet connection?如何处理后台 url 会话丢失互联网连接?
【发布时间】:2016-02-11 15:07:13
【问题描述】:

我有后台下载 zip 文件:

if let url = NSURL(string: urlstring) 
         {            
            let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier((NSUUID().UUIDString))
            let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
            let task = session.downloadTaskWithURL(url)
            session.sessionDescription = filepath
            if let sessionId = session.configuration.identifier
            {
                print("start zip session: " + sessionId)
            }

            task.resume()               
            }
        }

如果你有互联网连接,它会很好用,但如果你在下载应用程序期间丢失它,只需等待,并且 URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) 永远不会被调用。 如何处理?
类似于服务器响应的时间

【问题讨论】:

    标签: ios swift download background nsurlsession


    【解决方案1】:

    这个问题很老,但仍然没有答案,所以这里有一个解决方法。

    先做一些澄清

    一般URLSessionConfiguration 有一个属性称为waitsForConnectivity,可以设置为false,其中URLSessionTask 将在连接丢失时直接失败。但是,如果trueURLSessionTaskDelegate 将收到urlSession(_:taskIsWaitingForConnectivity:) 方法的回调。

    但是

    DownloadTask 等后台任务始终等待连接并忽略URLSessionConfigurationwaitsForConnectivity 属性。他们也不要触发urlSession(_:taskIsWaitingForConnectivity:)回调,所以没有官方的方法来监听下载任务的连接丢失。

    解决方法

    如果您监听下载进度,您会注意到对该方法的调用在一秒钟内完成了几次。因此,我们可以得出结论,如果超过 5 秒未调用进度回调,则可能存在连接中断问题。因此解决方法是为URLSessionDownloadDelegate 委托添加附加属性并存储进度的最后更新。然后有间隔函数定期检查这个属性是否没有很快更新。

    类似:

        class Downloader: NSObject, URLSessionTaskDelegate, URLSessionDownloadDelegate {
    
            var lastUpdate: Date;
            var downloadTask: URLSessionDownloadTask?;
    
            public var session : URLSession {
                get {
                    let config = URLSessionConfiguration.background(
                    withIdentifier: "\(Bundle.main.bundleIdentifier!).downloader");
                    config.isDiscretionary = true;
    
                    return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue());
                }
            }
    
            override init() {
                self.lastUpdate = Date();
                super.init();
            }
    
            func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
                // Handle download completition
                // ...
            }
    
            func urlSession(
                _ session: URLSession,
                downloadTask: URLSessionDownloadTask,
                didWriteData bytesWritten: Int64,
                totalBytesWritten writ: Int64,
                totalBytesExpectedToWrite exp: Int64)
            {
                let progress = 100 * writ / exp;
                // Do something with the progress
                // ...
    
                self.lastUpdate = Date();
            }
        }
    
        var downloader = Downloader();
        let url = "http://...";
        var request = URLRequest(url: URL(string: url)!);
        currentWorker.downloadTask = downloader.session.downloadTask(with: request);
        currentWorker.downloadTask!.resume();
    
        // Schedule timer for every 5 secs
        var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "CheckInternetDrop", userInfo: nil, repeats: true);
    
    func CheckInternetDrop(){
        let interval = Date().timeIntervalSinceDate(downloader.lastUpdate);
        if (interval > 5) {
            print("connection dropped");
        }
    }
    

    非常简单的例子...

    【讨论】:

    • 后台会话不需要 isDiscretionary,因为它们总是等待网络连接。
    【解决方案2】:

    根据pausing and resuming downloads 上的苹果文档:

    此外,使用后台配置的下载将自动处理恢复,因此仅非后台下载需要手动恢复。

    此外,waitsForConnectivity 被忽略的原因在downloading files in the background 中说明:

    如果您的应用在后台,系统可能会暂停您的应用,同时在另一个进程中执行下载。

    这就是为什么即使您以与 Dimitar Atanasov 类似的方式构建计时器,一旦应用程序进入后台,它也将无法工作,因为它将被暂停。

    我已经在网络故障的情况下测试了自己的后台下载,并且系统正常恢复,因此不需要额外的代码。

    【讨论】:

    • 帖子的作者提出了不同的问题!他知道当连接可用时,后台下载将继续。他在问是否有办法在发生这种情况时接收通知。无论是拔掉网线还是系统暂停后台进程,数据传输都会暂停。如果您正在构建一个显示速度和剩余时间的下载管理器,您很可能希望向用户显示下载已暂停。提供的解决方案不是最干净的,但没有官方方法 - 这就是为什么它被称为解决方法。
    【解决方案3】:

    您可以为您的请求设置超时:

    config.timeoutIntervalForRequest = <desired value>
    config.timeoutIntervalForResource = <desired value>
    

    文档:

    【讨论】:

    • 但如果我要下载一些大的东西,它会失败。下载时间取决于文件大小和互联网速度
    • 嗯,我想知道为什么您在失去连接时没有收到NSURLErrorNetworkConnectionLost
    • 我添加了 func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) 和 func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) 但是。当我失去连接时,他们不会被调用
    猜你喜欢
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 2023-04-03
    相关资源
    最近更新 更多