URLSession.datatask with request block not called in background

后端 未结 4 1066
轻奢々
轻奢々 2020-11-29 06:08

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 ge

相关标签:
4条回答
  • 2020-11-29 06:42

    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

    0 讨论(0)
  • 2020-11-29 06:46
      [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

    /*********************/

    0 讨论(0)
  • 2020-11-29 06:57

    Or simply start a BackgroundTask

    func send(...) {
      let backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
      let session = URLSession(configuration: .default)
    
      // ... after all the main logic, when you finish:
      DispatchQueue.main.async {
        completion(result)
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
      }
    }
    
    0 讨论(0)
  • 2020-11-29 07:03

    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 URLSession with 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.

    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:

    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        BackgroundSession.shared.savedCompletionHandler = completionHandler
    }
    
    0 讨论(0)
提交回复
热议问题