URLSessionDelegate functions not called for background upload on watchOS

Viewed 90

I'm using a Series 6 emulator on watchOS7 and I'm trying to upload some JSON data to a remote server using an URLSession background task. However the delegate functions are not being called so I cannot clean up any local data from the upload and handle any errors. I got the original idea from my implementation from this WWDC video WWDC Video. I've looked at many posts on the Internet but nothing I've tried seems to work. Here is my code:

UploadSession class

class UploadSession: NSObject, Identifiable, URLSessionDelegate {

var backgroundTasks = [WKURLSessionRefreshBackgroundTask]()

private lazy var urlSession: URLSession = {
    let config = URLSessionConfiguration.background(withIdentifier: "my.app.watchextension")
    config.sessionSendsLaunchEvents = true
    return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()

func enqueueBackgroundTask(idToken: String, uploadData: Data, url: URL) throws {
    //build the JSON object we want to send in this post request
    let tempDir = FileManager.default.temporaryDirectory
    let localURL = tempDir.appendingPathComponent("throwaway")
    try? uploadData.write(to: localURL)
    
    //set up the URLRequest
    var request = URLRequest(url: url)
    request.httpMethod = K.Upload.httpPost
    request.setValue(K.Upload.jsonContent, forHTTPHeaderField: K.Upload.contentType)
    request.setValue("\(K.Upload.bearer)\(idToken)", forHTTPHeaderField: K.Upload.authorization)
    request.timeoutInterval = K.Upload.httpUploadTimeout
    
    //keep a reference to this class
    BackgroundURLSessions.shared.sessions["my.app.watchextension"] = self
    
    //create the upload task and kick it off
    let task = urlSession.uploadTask(with: request, fromFile: localURL)
    task.earliestBeginDate = Date().advanced(by: 120)//when setting this to zero the upload runs straight away.
    task.resume()
}

func addBackgroundRefreshTask(_ task: WKURLSessionRefreshBackgroundTask) {
    backgroundTasks.append(task)
}

//gets called when the task background task completes
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    //PROBLEM. This delegate method is never called
    if let sessionId = session.configuration.identifier {
        
        //TODO delete any local data copies
        
        //set the session to nil so the system doesn't try to execute it again
        BackgroundURLSessions.shared.sessions[sessionId] = nil
    }
    for task in backgroundTasks {
        task.setTaskCompletedWithSnapshot(false)
    }
}

//gets called if the background task throws an error
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
    //PROBLEM. This delegate method is never called
}

}

BackgroundURLSessions class

class BackgroundURLSessions: NSObject {
static let shared: BackgroundURLSessions = BackgroundURLSessions()
var sessions = [String: UploadSession]()

override private init() {
    super.init()
}

}

Extension Delegate class

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
    // Use a switch statement to check the task type
    switch task {
    case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
        // Be sure to complete the URL session task once you’re done.
        if let session = BackgroundURLSessions.shared.sessions[urlSessionTask.sessionIdentifier] {
            session.addBackgroundRefreshTask(urlSessionTask)
        } else {
            urlSessionTask.setTaskCompletedWithSnapshot(false)
        }
    default:
        // make sure to complete unhandled task types
        task.setTaskCompletedWithSnapshot(false)
    }
}

}

Any help really appreciated as I'm really struggling to get this work and it's a vital part of the application. Thanks.

0 Answers
Related