xcode 带有请求块的 URLSession.datatask 未在后台调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44128358/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 09:59:47  来源:igfitidea点击:

URLSession.datatask with request block not called in background

iosswiftxcodexcode8nsurlsession

提问by Test Test

URLSessiondata task block is not calling when the app is in background and it stuck at dataTaskwith request.
When I open the app the block gets called. By the way I'm using httpsrequest.
This is my code:

URLSession当应用程序处于后台并停留在dataTask请求时,数据任务块不会调用。
当我打开应用程序时,块被调用。顺便说一句,我正在使用https请求。
这是我的代码:

    let request = NSMutableURLRequest(url: URL(string: url as String)!,

                                      cachePolicy: .reloadIgnoringCacheData,

                                      timeoutInterval:20)

    request.httpMethod = method as String

    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

    let session = URLSession.shared

    let data = params.data(using: String.Encoding.utf8.rawValue)

    request.httpBody = data

    session.dataTask(with: request as URLRequest,completionHandler:

        {(data, response, error) -> Void in

         if error == nil

            {

                do {

                    let result = try JSONSerialization.jsonObject(with: data!, options:

                        JSONSerialization.ReadingOptions.mutableContainers)

                    print(result)

                     completionHandler(result as AnyObject?,nil)

                }

                catch let JSONError as NSError{

                    completionHandler(nil,JSONError.localizedDescription as NSString?)

                }

            }

            else{

                completionHandler(nil,error!.localizedDescription as NSString?)                    

            }                

    }).resume()

Working perfectly when the app is in active state. Is there anything wrong in my code. please point me

当应用程序处于活动状态时完美运行。我的代码有什么问题吗。请指点我

回答by Rob

If you want downloads to progress after your app is no longer in foreground, you have to use background session. The basic constraints of background sessions are outlined in Downloading Files in Background, and are essentially:

如果您希望在您的应用程序不再处于前台后继续下载,您必须使用后台会话。在后台下载文件中概述了后台会话的基本约束,本质上是:

  1. Use delegate-based URLSessionwith background URLSessionConfiguration.

  2. Use upload and download tasks only, with no completion handlers.

  3. In iOS, Implement application(_:handleEventsForBackgroundURLSession:completionHandler:)app delegate, saving the completion handler and starting your background session.

    Implement urlSessionDidFinishEvents(forBackgroundURLSession:)in your URLSessionDelegate, calling that saved completion handler to let OS know you're done processing the background request completion.

  1. 使用基于委托的URLSession背景URLSessionConfiguration

  2. 仅使用上传和下载任务,没有完成处理程序。

  3. 在 iOS 中,实现application(_:handleEventsForBackgroundURLSession:completionHandler:)应用程序委托,保存完成处理程序并启动后台会话。

    urlSessionDidFinishEvents(forBackgroundURLSession:)在您的 中实现URLSessionDelegate,调用保存的完成处理程序,让操作系统知道您已完成后台请求完成处理。

So, pulling that together:

所以,把它放在一起:

func startRequest(for urlString: String, method: String, parameters: String) {
    let url = URL(string: urlString)!
    var request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 20)
    request.httpMethod = method
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.httpBody = parameters.data(using: .utf8)
    BackgroundSession.shared.start(request)
}

Where

在哪里

class BackgroundSession: NSObject {
    static let shared = BackgroundSession()

    static let identifier = "com.domain.app.bg"

    private var session: URLSession!

    #if !os(macOS)
    var savedCompletionHandler: (() -> Void)?
    #endif

    private override init() {
        super.init()

        let configuration = URLSessionConfiguration.background(withIdentifier: BackgroundSession.identifier)
        session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }

    func start(_ request: URLRequest) {
        session.downloadTask(with: request).resume()
    }
}

extension BackgroundSession: URLSessionDelegate {
    #if !os(macOS)
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        DispatchQueue.main.async {
            self.savedCompletionHandler?()
            self.savedCompletionHandler = nil
        }
    }
    #endif
}

extension BackgroundSession: URLSessionTaskDelegate {
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            // handle failure here
            print("\(error.localizedDescription)")
        }
    }
}

extension BackgroundSession: URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        do {
            let data = try Data(contentsOf: location)
            let json = try JSONSerialization.jsonObject(with: data)

            print("\(json)")
            // do something with json
        } catch {
            print("\(error.localizedDescription)")
        }
    }
}

And the iOS app delegate does:

iOS 应用程序委托执行以下操作:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundSession.shared.savedCompletionHandler = completionHandler
}

回答by rameez

You need a background session. The URLSessionDataTask which as per Apple's documentation doesn't support background downloads.

您需要一个后台会话。根据 Apple 的文档, URLSessionDataTask 不支持后台下载。

Create a URLSessionDownloadTaskand use its delegate method it should work.

创建一个URLSessionDownloadTask并使用它应该工作的委托方法。

Follow this link

按照这个链接

回答by Ajjjjjjjj

  [URLSessionDownloadTask setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
                CGFloat percentDone = (double)(totalBytesWritten)/(double)totalBytesExpectedToWrite;
                [SVProgressHUD showWithStatus:[NSString stringWithFormat:@"%.2f%%",percentDone*100]];

            }];

        [downloadTask resume];

// Apply as shown in picture

// 如图所示应用

/*********************/enter image description here

/*********************/在此处输入图片说明