URLSession.datatask с блоком запроса не вызывается в фоновом режиме
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()
Отлично работает, когда приложение находится в активном состоянии. Есть ли что-то не так в моем коде. пожалуйста, укажите мне
3 ответа
Если вы хотите, чтобы загрузка продолжалась после того, как ваше приложение перестало быть на переднем плане, вы должны использовать фоновый сеанс. Основные ограничения фоновых сеансов изложены в руководстве по программированию сеансов URL: использование NSURLSession: соображения фоновой передачи и по существу:
Использовать на основе делегатов
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
}
Или просто начните
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)
}
}
Вам нужен фоновый сеанс. URLSessionDataTask, который согласно документации Apple не поддерживает фоновые загрузки.
Создать URLSessionDownloadTask
и использовать его метод делегата, он должен работать.
Перейдите по этой ссылке
[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];
// Применить, как показано на рисунке