URLSession.datatask с блоком запроса не вызывается в фоновом режиме
URLSession
блок задач data не вызывает, когда приложение находится в фоновом режиме, и оно застряло в 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()
Отлично работает, когда приложение находится в активном состоянии. Есть ли что-нибудь неправильное в моем коде? пожалуйста, укажи мне
3 ответа:
Если вы хотите, чтобы загрузка выполнялась после того, как ваше приложение больше не находится на переднем плане, вы должны использовать фоновую сессию. Основные ограничения фоновых сессий изложены в руководстве по программированию сеансов URL: Using NSURLSession: Background Transfer Considerations , и по существу:
Используйте делегат на основе
URLSession
с фономURLSessionConfiguration
.Используйте только задачи загрузки и выгрузки, без обработчиков завершения.
Реализовать
application(_:handleEventsForBackgroundURLSession:completionHandler:)
в делегате приложения сохраните обработчик завершения и запустите фоновый сеанс.Реализовать
urlSessionDidFinishEvents(forBackgroundURLSession:)
в вашемURLSessionDelegate
вызове сохраненного обработчика завершения, чтобы ОС знала, что вы закончили обработку завершения фонового запроса.Итак, собирая это вместе:
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) }
Где
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)") } } }
И делегат приложения делает:
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { BackgroundSession.shared.savedCompletionHandler = completionHandler }
[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];
// применить, как показано на рисунке