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"
}