我想使用session.updateApplicationContext(applicationContext).
当手表上的应用处于活动状态时发送应用程序联系人可以正常工作
当我激活手表上的主页按钮时,手表应用程序将移至后台,调用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
。毕竟,这个演示项目应该正好演示这一点
也许有人可以尝试演示项目并确认这个问题。
有什么问题?
答案 0 :(得分:6)
当watchOS扩展程序WKWatchConnectivityRefreshBackgroundTask
处于WCSession
状态并且扩展程序未在前台运行时(后台运行),当前notActivated
仅在watchOS模拟器上被确认或终止)。
在真实设备中,我的测试中不会调用它。但Apple医生说它可能。因此,在Apple更改其文档之前,您不应该依赖它。
对于WCSession
,当它为activated
时,您可以传输userInfo,当对应方处于活动状态时,它可以获取userInfo。对手不需要在前台被激活,它可以处于高优先级的背景中。
以下是我的测试结果。
WCSession
notActivated
?WCSession.activate()
。默认情况下WCSession
为notActivated
。-------------以下是旧帖子,如果你不想阅读,可以安全地忽略.---------- -----
请先看图片,然后我会解释。
由于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中,选择total
为product->scheme
,以便我们可以在Xcode中终止watchOS应用。
WatchKit app
更改为4。label
(或cmd +。)。 watchOS应用程序将消失。product->stop
更改1乘以您的点击次数。答案 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周后,我没有得到任何回复。
也许我错了,有人可以给我一个如何做正确的提示。