transmission hangs on cellular with background NSURLSession under Watchkit 4

I am developing a Watchkit application that should be able to run stand-alone over cellular on Watch Series 3. I am using WatchOS 4.1 and iOS 11.1. I had the same issue with WatchOS 4.

The application downloads a small file using background NSURLSession.

The download works perfect when the watch is connected to the iPhone, but does not work when the watch is disconnected from the iPhone but connected to either Wifi or cellular. In my code below, the status never changes from "Download Starting". None of the urlSession callbacks are triggered. The application just hangs.


Of course, the core Apple applications such as Maps and Music work fine over cellular or wifi.


I checked under settings->cellular. On the iPhone my application is showing up. Under the Watch settings it is not. Are there any entries we have to make to the settings bundle?


Below is my code:

Module: Watchkit Extension -> InterfaceController.swift


public static func download(_ url: String, SessionID id: String, delegate: URLSessionDelegate? ){

let config = URLSessionConfiguration.background(withIdentifier: id)

config.waitsForConnectivity = true

config.allowsCellularAccess = true

config.isDiscretionary = true


let session = URLSession(configuration: config, delegate: delegate, delegateQueue: OperationQueue())

let req = URLRequest(url: URL(string:url)!)

status = "Download starting"

session.downloadTask(with: req).resume()

}


//Download complete with no errors

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {

var loaded = false

let fm = FileManager()

let url = try! fm.url(for: .documentDirectory,

in: .userDomainMask,

appropriateFor: location, create: true).appendingPathComponent("localfile.txt")

do{

try fm.removeItem(at: url ) //delete previously downloaded files

}

catch let err{

status = "Error = \(err)"

print(status)

}

do{

try fm.moveItem(at: location, to: url)

status = "Download finished"

print( status)

loaded = true

} catch let err{

status = "Error = \(err)"

print(status)

}

session.invalidateAndCancel() // important in order for a second downoad to work

if loaded{

let textString = try! String(contentsOf: url as URL)

}

}


// File is downloading ... update status

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

status = "Downloaded \(bytesWritten) bytes..."

}


//Download interupted but resuming

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {

status = "Resuming the download"

}


//Download complete with errors

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {

if let err = error{

status = "Completed with an error = \(err)"

} else {

status = "Finished"

}

}


//Download invalid

func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {

if let err = error{

status = "Invalidated \(err)"

}

}


//Waiting for connectivity

func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {

status = "Waiting for Connectivity"

}

Replies

same question, do you have some ideas?

Turn off isDiscretionary flag