URLSession.datatask with request block not called

2019-01-15 04:16发布

URLSession data task block is not calling when the app is in background and it stuck at dataTask with request.
When I open the app the block gets called. By the way I'm using https request.
This is my code:

    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

3条回答
SAY GOODBYE
2楼-- · 2019-01-15 04:41

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

Create a URLSessionDownloadTask and use its delegate method it should work.

Follow this link

查看更多
We Are One
3楼-- · 2019-01-15 04:41
  [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

查看更多
男人必须洒脱
4楼-- · 2019-01-15 04:55

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 URL Session Programming Guide: Using NSURLSession: Background Transfer Considerations, and are essentially:

  1. Use delegate-based URLSession with background URLSessionConfiguration.

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

  3. Implement application(_:handleEventsForBackgroundURLSession:completionHandler:) in your 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.

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!

    var savedCompletionHandler: (() -> Void)?

    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 {
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        DispatchQueue.main.async {
            self.savedCompletionHandler?()
            self.savedCompletionHandler = nil
        }
    }
}

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 app delegate does:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundSession.shared.savedCompletionHandler = completionHandler
}
查看更多
登录 后发表回答