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

Rei*_*ner 2 background-task watchconnectivity watchos-3

我想用iPhone在后台更新我的手表应用程序状态 session.updateApplicationContext(applicationContext).

在手表上的应用程序处于活动状态时发送应用程序联系人可以正常工作.
当我激活手表上的主页按钮时,手表应用程序会进入后台,handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)被呼叫并WKSnapshotRefreshBackgroundTask提供一个.

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

Apple的文档说:" 当您从配对的iPhone接收后台数据时,系统会在后台启动您的应用程序,实例化一个WKWatchConnectivityRefreshBackgroundTask对象,并将任务对象传递给您的扩展委托的handleBackgroundTasks:方法.".

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

编辑:

为了检查可能出错的地方,我下载了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()
}
Run Code Online (Sandbox Code Playgroud)

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

怎么了?

Owe*_*hao 6

更新我的回答


结论首先

WKWatchConnectivityRefreshBackgroundTask当watchOS扩展WCSession处于notActivated状态且扩展未在前台运行(在后台或终止)时,目前仅在watchOS Simulator上调用.

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

WCSession核心

WCSession核心

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

测试结果

这是我的测试结果.

在模拟器和设备中

怎么做WCSession notActivated

  1. 使用Xcode终止watchOS扩展.Xcode会向你的WKExtension发送一个kill信号.
  2. 或者不要WCSession.activate()在watchOS Extension端的代码中运行.由于WCSessionnotActivated在默认情况下.

-------------下面是旧帖子,如果你不想阅读,可以安全地忽略.-------------------

理论

在此输入图像描述

请先看图片然后我会解释.

由于watchOS的历史,有WCSessionDelegate接收功能(从watchOS 2.0开始)和WKExtensionDelegate.handle(_:)功能(从watchOS 3.0开始).

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

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

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

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

如果您在大多数情况下都实现了它们,则数据将根据watchOS应用程序的状态进行处理,并且永远不会排队.


如何证明?

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

session.transferUserInfo(["send test":""])
Run Code Online (Sandbox Code Playgroud)

在watchOS应用程序中,添加标签interface.storyboard,然后将其拖动viewController@IBOutlet var label: WKInterfaceLabel!,并实现两者WKExtensionDelegate.handle(_:)func session(WCSession, didReceiveUserInfo: [String : Any] = [:]) 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))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果WKExtensionDelegate.handle(_:)运行,我们加total1.如果func session(WCSession, didReceiveUserInfo: [String : Any] = [:])运行,我们加total4.

调试

在Xcode中,选择product->schemeas WatchKit app,我们可以在Xcode中终止watchOS应用程序.

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