Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
476 views
in Technique[技术] by (71.8m points)

watchkit - WKURLSessionRefreshBackgroundTask isn't called when attempting to do background refreshes in watchOS

I'm working on a complication to get scheduled data from a web service. Every 20-30 minutes (or manually), I am scheduling a WKRefreshBackgroundTask to do this.

As suggested by Apple, I want the OS to handle the fetching of this data via a background NSURLSession.

This is the function I use to download the data I need:

func scheduleURLSession()
{
    print("
Scheduling URL Session...")

    let backgroundSessionConfig:URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString)
    backgroundSessionConfig.sessionSendsLaunchEvents = true

    let backgroundSession = URLSession(configuration: backgroundSessionConfig)

    let downloadTask = backgroundSession.downloadTask(with: URL(string: "https://www.myserver.com/somedata")!)
    downloadTask.resume()
}

A few things about this:

  1. It does get called when I schedule it. I see its print statement in the console.
  2. It's nearly identical to Apple's example.
  3. I've omitted the URL. That same URL works in the iOS/watchOS apps just fine so nothing is wrong with it.

The problem is, even though I am calling resume() on the task and allowing it to wake my app when it is complete, it doesn't seem to do either.

When it completes, it should be coming back to a WKExtensionDelegate handler:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)

as a WKURLSessionRefreshBackgroundTask, but it does not.

My code, identical to Apple's sample code, then creates another session but rejoins it via the WKURLSessionRefreshBackgroundTask's identifier. This is where the delegate is set in order to process the downloaded data. Check the code:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    for task in backgroundTasks {
        switch task {

        case let backgroundTask as WKApplicationRefreshBackgroundTask:
            print("
WatchKit - WKApplicationRefreshBackgroundTask")
            // self.updateComplicationDataArrivalTimes(backgroundTask)
            self.scheduleURLSession()
            backgroundTask.setTaskCompleted()

        case let snapshotTask as WKSnapshotRefreshBackgroundTask:
            // Snapshot tasks have a unique completion call, make sure to set your expiration date
            print("
WatchKit - WKSnapshotRefreshBackgroundTask")
            snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)

        case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
            print("
WatchKit - WKWatchConnectivityRefreshBackgroundTask")
            connectivityTask.setTaskCompleted()

        case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
            print("
WatchKit - WKURLSessionRefreshBackgroundTask")
            let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: urlSessionTask.sessionIdentifier)
            let backgroundSession = URLSession(configuration: backgroundConfigObject, delegate: self, delegateQueue: nil)

            print("Rejoining session ", backgroundSession)
            urlSessionTask.setTaskCompleted()

        default:
            // make sure to complete unhandled task types
            task.setTaskCompleted()
        }
    }
}

But again, it doesn't seem to ever come back. I can't seem to figure out why this is working despite the code is identical to Apple's sample code for this project: WatchBackgroundRefresh: Using WKRefreshBackgroundTask to update WatchKit apps in the background.

Is there some setting in my project that I am missing? I am putting all this code in the ExtensionDelegate, new in watchOS 3. I am also conforming to WKExtensionDelegate and URLSessionDownloadDelegate.

Thanks for your help in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I got it working! I started out by looking a lot at the WWDC'16 videoes/notes, comparing them to the WatchBackgroundRefresh example from Apple. Then, while browsing the Apple Dev forums, I found this thread, with the same problem we encountered. There, a guy, "Daniel Fontes" posts his 'recipe' for getting it to work (note, not the accepted answer!), and that combined with the videos worked for me.

What I did to make the Apple example work:

  1. Make the MainInterfaceController an URLSessionDelegate
  2. Create a local variable: var savedTask:WKRefreshBackgroundTask?
  3. In the handle( backgroundTasks:) function, save the WKURLSessionRefreshBackgroundTaskto the local variable self.savedTask = task - do not task.setTaskCompleted() (!!)
  4. In the urlSession - didFinishDownloading:, set the saved task to completed: self.savedTask?.setTaskCompleted() after you've read the data received.
  5. Ensure that the resource you are accessing is https://, otherwise add the "App Transport Security Settings" to your Info.plist file.

Hope this can help!

ps. this works in the simnulator (xcode 8.3.3, watchOS 3.2)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...