0

Je commence un téléchargement dans une extension d'action (ActionRequestHandler) comme ceci:URLSessionDownloadDelegate didFinishDownloadingTo pas appelé en arrière-plan

private lazy var urlSession: URLSession = { 
    let config = URLSessionConfiguration.background(withIdentifier: "de.stefantrauth.Downloader") 
    config.sharedContainerIdentifier = "group.de.stefantrauth.Downloader" 
    return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main) 
}() 

private func initiateDownloadOfFileFrom(url: URL) { 
    urlSession.downloadTask(with: url).resume() 
    completeRequest() // this tells the system the action extension is done with its work 
} 

Ensuite, le téléchargement est traité par iOS en arrière-plan.

Je veux maintenant gérer le téléchargement fini dans mon application principale AppDelegate, parce que c'est ce que iOS appelle lorsque le téléchargement est terminé.

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping() -> Void) { 
    print("handleEventsForBackgroundURLSession") 
    urlSessionBackgroundCompletionHandler = completionHandler 
} 

Cette méthode est appelée en arrière-plan après un certain temps comme prévu.

Mes AppDelegate implémente également URLSessionDelegate et URLSessionDownloadDelegate pour traiter les mises à jour pour le téléchargement.

Particulièrement intéressants sont

func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { 
    DispatchQueue.main.async { 
     print("urlSessionDidFinishEvents") 
     self.urlSessionBackgroundCompletionHandler?() 
     self.urlSessionBackgroundCompletionHandler = nil 
    } 
} 

et

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { 
    print("download finished to \(location.absoluteString)") 
    do { 
     let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) 
     let savedURL = documentsURL.appendingPathComponent(location.lastPathComponent) 
     try FileManager.default.moveItem(at: location, to: savedURL) 
     print("moved file to: \(savedURL.absoluteString)") 
    } catch { 
     print ("file error: \(error)") 
    } 
} 

Les deux urlSessionDidFinishEvents et didFinishDownloadingTone sont pas appelés après handleEventsForBackgroundURLSession été appelé en arrière-plan. Ce n'est qu'après avoir relancé l'application au premier plan que les méthodes déléguées sont appelées. Pourquoi ne sont-ils pas appelés et qu'est-ce que je peux faire pour résoudre ce problème?

J'ai essayé de créer le URLSession dans handleEventsForBackgroundURLSession comme ceci:

private func initUrlSessionWith(identifier: String) { 
    let config = URLSessionConfiguration.background(withIdentifier: identifier) 
    config.sharedContainerIdentifier = "group.de.stefantrauth.Downloader" 
    urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main) 
} 

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping() -> Void) { 
    print("handleEventsForBackgroundURLSession") 
    initUrlSessionWith(identifier: identifier) 
    urlSessionBackgroundCompletionHandler = completionHandler 
} 

Cependant, cela n'a pas résolu le problème.

Avant de demander: Oui, je le teste sur un périphérique réel car le simulateur a des problèmes avec la gestion des tâches d'arrière-plan.

+0

J'ai l'impression que ce problème est spécifique aux extensions, parce que le code me convient; c'est probablement une question de Quinn. Demandez sur les forums des développeurs. En termes de conseils généraux, il n'y a aucune raison d'exécuter les rappels de session sur le thread principal; vous envoyez déjà le callback critique sur le thread principal. Il suffit de passer rien. Mais je suis assez sûr que ce n'est pas la cause de votre problème. – dgatwood

Répondre

0

Mon code est réellement correct. Juste ma façon de déboguer était le problème. Après avoir utilisé la consignation de console au lieu de déboguer via Xcode, cela fonctionnait correctement.

Voir https://forums.developer.apple.com/message/263807#263807 pour plus de détails sur l'utilisation du débogage de session d'url en arrière-plan.