WKWatchConnectivityRefreshBackgroundTask永远不会在后台触发,但是WKSnapshotRefreshBackgroundTask

时间:2016-11-10 21:08:12

标签: background-task watchconnectivity watch-os-3

我想使用session.updateApplicationContext(applicationContext).

在iPhone的后台更新我的观看应用状态

当手表上的应用处于活动状态时发送应用程序联系人可以正常工作 当我激活手表上的主页按钮时,手表应用程序将移至后台,调用handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>),并提供WKSnapshotRefreshBackgroundTask

所以我不明白为什么WKSnapshotRefreshBackgroundTask被正确触发,而不是WKWatchConnectivityRefreshBackgroundTask

Apple’s docs说“当您从配对的iPhone接收背景数据时,系统会在后台启动您的应用,实例化WKWatchConnectivityRefreshBackgroundTask对象,并将任务对象传递给您的扩展代表handleBackgroundTasks:method。“。

但这不会发生在设备上,也不会发生在模拟器上。可能有什么不对?

修改:

为了检查可能出错的地方,我下载了可以下载here的Apple的演示项目“QuickSwitch”。以下是应该处理后台任务的代码:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    for backgroundTask in backgroundTasks {
        if let wcBackgroundTask = backgroundTask as? WKWatchConnectivityRefreshBackgroundTask {
            // store a reference to the task objects as we might have to wait to complete them
            self.wcBackgroundTasks.append(wcBackgroundTask)
        } else {
            // immediately complete all other task types as we have not added support for them
            backgroundTask.setTaskCompleted()
        }
    }
    completeAllTasksIfReady()
}

在那里,同样的事情
我确实在if语句的行中设置了一个breakponint并执行了应用程序 按下手表模拟器上的主页按钮时,将使用WKSnapshotRefreshBackgroundTask到达断点。这没关系(见上文) 但是,如果在iPhone模拟器上选择了不同的行,则 watchOS不会按预期安排WKWatchConnectivityRefreshBackgroundTask 。毕竟,这个演示项目应该正好演示这一点 也许有人可以尝试演示项目并确认这个问题。

有什么问题?

2 个答案:

答案 0 :(得分:6)

更新我的回答

结论第一

当watchOS扩展程序WKWatchConnectivityRefreshBackgroundTask处于WCSession状态并且扩展程序未在前台运行时(后台运行),当前notActivated仅在watchOS模拟器上被确认或终止)。

在真实设备中,我的测试中不会调用它。但Apple医生说它可能。因此,在Apple更改其文档之前,您不应该依赖它。

WCSession核心

WCSession Core

对于WCSession,当它为activated时,您可以传输userInfo,当对应方处于活动状态时,它可以获取userInfo。对手不需要在前台被激活,它可以处于高优先级的背景中。

测试结果

以下是我的测试结果。

In Simulators and in devices

如何制作WCSession notActivated

  1. 使用Xcode终止watchOS扩展。 Xcode会向你的WKExtension发送一个终止信号。
  2. 或者不要在watchOS Extension端的代码中运行WCSession.activate()。默认情况下WCSessionnotActivated
  3. -------------以下是旧帖子,如果你不想阅读,可以安全地忽略.---------- -----

    理论

    enter image description here

    请先看图片,然后我会解释。

    由于watchOS的历史,有两个WCSessionDelegate接收函数(从watchOS 2.0开始)和WKExtensionDelegate.handle(_:)函数(从watchOS 3.0开始)。

    虽然他们都声称是后台处理,但前者仅在您的应用处于前台时立即生效。如果您的应用不在前台(在后台或被终止),数据将排队,并在您的应用再次进入前台后立即执行。

    WKExtensionDelegate.handle(_:)确实在后台工作。但是,WKExtensionDelegate.handle(_:)是可选的,但如果您使用Xcode,建议并做好充分准备。

    如果您未通过评论来实施WKExtensionDelegate.handle(_:)。你的应用程序以watchOS 2.0方式工作。

    如果您实施WKExtensionDelegate.handle(_:),但您的watchOS应用中没有WCSession。结果很棘手。当您观看OS应用程序位于前台时,您不会获得任何数据,因为您没有WCSession。当您的应用处于后台时,它会在数据到来时被唤醒,但您无法获得数据,因为您没有会话。

    如果您在大多数情况下同时实施了这些数据,则会根据watchOS应用的状态处理数据,并且永远不会排队。

    如何证明?

    创建一个新的watchOS项目。在iOS部分中,添加一个按钮,每次单击该按钮时,都会向userOS发送userInfo

    session.transferUserInfo(["send test":""])
    

    在您的watchOS应用中,在interface.storyboard中添加标签,并将其拖至viewController @IBOutlet var label: WKInterfaceLabel!,并同时实施WKExtensionDelegate.handle(_:)func session(WCSession, didReceiveUserInfo: [String : Any] = [:]) {{ 1}}。

    appDelegate

    如果var total = 0 func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one. for task in backgroundTasks { // Use a switch statement to check the task type switch task { case let backgroundTask as WKApplicationRefreshBackgroundTask: // Be sure to complete the background task once you’re done. backgroundTask.setTaskCompleted() case let snapshotTask as WKSnapshotRefreshBackgroundTask: // Snapshot tasks have a unique completion call, make sure to set your expiration date snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil) case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask: // Be sure to complete the connectivity task once you’re done. total += 1 DispatchQueue.main.async { if let viewController = WKExtension.shared().rootInterfaceController as? InterfaceController { viewController.label.setText(String(self.total)) } } connectivityTask.setTaskCompleted() case let urlSessionTask as WKURLSessionRefreshBackgroundTask: // Be sure to complete the URL session task once you’re done. urlSessionTask.setTaskCompleted() default: // make sure to complete unhandled task types task.setTaskCompleted() } } } public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) { total += 4 DispatchQueue.main.async { if let viewController = WKExtension.shared().rootInterfaceController as? InterfaceController { viewController.label.setText(String(self.total)) } } } 运行,我们会将WKExtensionDelegate.handle(_:)加1。如果total运行,我们会将func session(WCSession, didReceiveUserInfo: [String : Any] = [:])加4。

    调试

    在Xcode中,选择totalproduct->scheme,以便我们可以在Xcode中终止watchOS应用。

    1. 运行项目。
    2. 当watchOS应用显示时,手动打开iOS应用。
    3. 点击iOS应用中的按钮。您可以看到watchOS中的WatchKit app更改为4。
    4. 在Xcode中,点击label(或cmd +。)。 watchOS应用程序将消失。
    5. 在iOS应用按钮上单击一次或多次。然后手动打开watchOS应用程序。您会看到这次product->stop更改1乘以您的点击次数。
    6. 当watchOS应用程序处于前台时,该步骤将再次为4。

答案 1 :(得分:1)

对所有有同样问题的人:
我将问题提交给Apple Developer Technical Support,他们确认了(#652471299)watchOS 3中的问题,并建议提交错误报告,我做了什么(#29284559)。
因此,必须等待Apple修复错误。

更新:

他们在2天后回答了我的错误报告:

我们得到了很多像这样的问题,通常是对时间的一些误解或者应用程序没有暂停,因为它正在调试或不在Dock中调试,所以它不会得到任意的任务。 在这种情况下,阅读上面的描述我猜测用户在测试时通过xcode进行调试。两种任务类型:Watch Connectivity和URLSession仅作为“启动”事件到达。在调试时,xcode使应用程序保持运行,因此它永远不会完成这些任务。测试此功能的最佳方法是断开与xcode的连接并测试,确保您的应用程序也在扩展坞中 - 只有停靠的应用程序才能获得自行决定的任务。
如果你在尝试之后看到它不起作用,我们需要一个sysdiagnose更进一步。

我认为这种说法是错误的。我的回复是:

感谢您的快速回答。但是,无论如何都有问题: 功能

handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)

应处理所有后台任务,包括WKWatchConnectivityRefreshBackgroundTask

要检查不是这种情况很容易: 只需在安排了这样的后台任务时让应用程序崩溃,即在Apple的QuickSwitch演示项目中插入始终为assert的{​​{1}}语句:

false

然后在前台,停靠栏或后台运行应用程序,并在iPhone上选择不同的代码。 该应用不会崩溃,这证明没有安排func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { for backgroundTask in backgroundTasks { if let wcBackgroundTask = backgroundTask as? WKWatchConnectivityRefreshBackgroundTask { assert(false) // If the app comes here, it will crash // store a reference to the task objects as we might have to wait to complete them self.wcBackgroundTasks.append(wcBackgroundTask) } else { // immediately complete all other task types as we have not added support for them backgroundTask.setTaskCompleted() } } completeAllTasksIfReady() } 请在没有Xcode控制的情况下进行此测试。只需在iPhone和iPhone上运行它手表设备。

现在,1周后,我没有得到任何回复。

也许我错了,有人可以给我一个如何做正确的提示。