handle never invoked with WKURLSessionRefreshBackgroundTask type

Hi Folks,

I am building a SwiftUI based WatchOS app primarily focused on updating a complication using data from a REST API call.

I am trying to reproduce the approach to updating complications in the background as described in "Keeping your complications up to date".

The trouble I have is that the func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) method on the ExtensionDelegate is never called for the WKURLSessionRefreshBackgroundTask task type. The handle method is invoked for other task types such as WKSnapshotRefreshBackgroundTask.

After some refactoring, I have deviated from the approach in the video and I now reshedule the background task in the func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) method of the URLSessionDownloadDelegate.

This works fine, and the tasks are being resheduled in the background, but my concern is that there maybe a WKURLSessionRefreshBackgroundTask object lurking in the background for which I haven't called setTaskCompletedWithSnapshot.

My session is configured as follows:

private  lazy  var backgroundURLSession: URLSession  = {
    let appBundleName = Bundle.main.bundleURL.lastPathComponent.lowercased().replacingOccurrences(of: " ", with: ".")
    let sessionIdentifier = "com.gjam.liffeywatch.\(appBundleName)"

    let config =  URLSessionConfiguration .background(withIdentifier: sessionIdentifier)

    config.isDiscretionary =  false
    config.sessionSendsLaunchEvents =  true
    config.requestCachePolicy = .reloadIgnoringLocalCacheData
    config.urlCache = nil
    return  URLSession (configuration: config, delegate: self , delegateQueue: nil )
}()

and the scheduling code is a follows:

func schedule(_ first: Bool) {
    print("Scheduling background URL session")
    let bgTask = backgroundURLSession.downloadTask(with: LiffyDataProvider.url)

    #if DEBUG
    bgTask.earliestBeginDate = Date().addingTimeInterval(first ? 10 : 60 * 2)
    #else
    bgTask.earliestBeginDate = Date().addingTimeInterval(first ? 30 : 60 * 60 * 2)
    #endif

    bgTask.countOfBytesClientExpectsToSend = 200
    bgTask.countOfBytesClientExpectsToReceive = 1024
    bgTask.resume()

    print("Task started")
    backgroundTask = bgTask
}

Does anyone have any idea's why the handle method is not invoked with WKURLSessionRefreshBackgroundTask tasks?

Cheers,

Gareth.

moved

Hi Folks,

I have made some progress on understanding what is going on. Testing and debugging is quite challenging, but here are some observations:

  1. The handle:backgroundTasks: method of the WKExtensionDelegate never seems to fire in the simulator.

  2. You are at mercy of the system as to when the scheduled tasks will execute. This is by design, and will depend on conditions so it is hard to anitcipate when the requests will actually execute when debugging (i.e. don't expect the system to execute the task soon after the earliestBeginDate you have set for the task).

  3. There seems to be a type of "flush" of outstanding tasks when the app is activated and brought to the foreground. This leads to a bug in the sample code from the video. When these tasks are "flushed", there is no closure set (Set in the handle:backgroundTasks: method by calling the refresh method on the data provider (URLSessionDownloadDelegate)) which rescheduled the next background task. As such the polling mechanism is essentially breaks.

So far, the solution is to only set the WKURLSessionRefreshBackgroundTask to complete in the closure and have the rescheduling done every time in the didCompleteWithError of the URLSessionDownloadDelegate. This may not be the optimal solution - Some additional investigation required for this.

handle never invoked with WKURLSessionRefreshBackgroundTask type
 
 
Q