我正在研究一种复杂的方法,以从网络服务获取预定数据。每隔 20-30 分钟(或手动),我会安排一个 WKRefreshBackgroundTask 来执行此操作。
按照 Apple 的建议,我希望操作系统通过后台 NSURLSession
处理此数据的获取。
这是我用来下载我需要的数据的函数:
func scheduleURLSession()
{
print("\nScheduling 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()
}
关于此的一些事情:
- 当我安排它时,它确实会被调用。我在控制台中看到了它的打印语句。
- 它与 Apple 的示例几乎相同。
- 我省略了网址。同样的 URL 在 iOS/watchOS 应用程序中工作得很好,所以没有任何问题。
问题是,即使我在任务上调用 resume()
并允许它在完成时唤醒我的应用程序,但它似乎也没有这样做。
完成后,它应该返回到 WKExtensionDelegate 处理程序:
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)
作为 WKURLSessionRefreshBackgroundTask
,但事实并非如此。
我的代码与 Apple 的示例代码相同,然后创建另一个 session ,但通过 WKURLSessionRefreshBackgroundTask
的标识符重新加入它。这是设置委托(delegate)的位置,以便处理下载的数据。检查代码:
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
print("\nWatchKit - 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("\nWatchKit - WKSnapshotRefreshBackgroundTask")
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
print("\nWatchKit - WKWatchConnectivityRefreshBackgroundTask")
connectivityTask.setTaskCompleted()
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
print("\nWatchKit - 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()
}
}
}
但是,它似乎再也不会回来了。我似乎无法弄清楚为什么这是有效的,尽管该代码与 Apple 该项目的示例代码相同: WatchBackgroundRefresh: Using WKRefreshBackgroundTask to update WatchKit apps in the background .
我的项目中是否缺少某些设置?我将所有这些代码放入 watchOS 3 中新增的 ExtensionDelegate
中。我还遵守 WKExtensionDelegate
和 URLSessionDownloadDelegate
。
提前感谢您的帮助!
最佳答案
我成功了!我首先看了很多 WWDC'16 视频/笔记,并将它们与 WatchBackgroundRefresh 进行比较。来自苹果公司的例子。然后,在浏览Apple Dev论坛时,我发现this thread ,与我们遇到的问题相同。在那里,一个叫“Daniel Fontes”的人发布了他的“秘诀”,以使其发挥作用(注意,不是公认的答案!),这与视频相结合对我有用。
为了使 Apple 示例正常工作,我做了什么:
- 将 MainInterfaceController 设为 URLSessionDelegate
- 创建局部变量:
var savedTask:WKRefreshBackgroundTask?
- 在
handle( backgroundTasks:)
函数,保存WKURLSessionRefreshBackgroundTask
到局部变量self.savedTask = task
- 不要使用task.setTaskCompleted() (!!) - 在
urlSession - didFinishDownloading:
,将保存的任务设置为已完成:self.savedTask?.setTaskCompleted()
阅读收到的数据后。 - 确保您访问的资源是 https://,否则将“应用程序传输安全设置”添加到您的 Info.plist 文件中。
希望这能有所帮助!
ps。这适用于模拟器(xcode 8.3.3,watchOS 3.2)
关于watchkit - 尝试在 watchOS 中进行后台刷新时不会调用 WKURLSessionRefreshBackgroundTask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41156386/