WCSession 的 transferUserInfo 在 iOS 9.3 的 watchOS 2.2 中不再可靠地工作
WCSession's transferUserInfo no longer reliably working in watchOS 2.2 with iOS 9.3
我有一个现有的 iOS 9.2 和 watchOS 2.1 应用程序,它使用 sendMessage
和 transferUserInfo
将数据从 iPhone 发送到 Apple Watch。如果 sendMessage
失败,我正在使用 transferUserInfo
将数据排队等待稍后交付:
// *** In the iOS app ***
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
// *** In the watchOS app ***
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
// Handle message here
}
func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
// Handle message here
}
在不更改任何代码的情况下,运行 iOS 9.3 上的应用程序在真实设备上使用 watchOS 2.2(模拟器没有相同的问题),sendMessage
将数据传送到Apple Watch 只要手表在范围内并且屏幕打开。这是预期的,也是它以前的工作方式。但是,如果屏幕关闭并且 sendMessage
失败,当屏幕重新打开时 transferUserInfo
不再向 Apple Watch 传输数据。
为了找出出错的地方,我添加了以下 WCSessionDelegate
方法来查看 iOS 应用程序是否无法发送数据:
func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: NSError?) {
// Called when self.session.transferUserInfo completes
}
调用 transferUserInfo
后确实会调用此方法,但没有返回任何错误,iOS 应用程序似乎表明传输成功。
一开始我以为可能传输数据的时间变长了,但是放了一天数据还是没有传输。我现在有点怀疑它与新的多手表 API 有关,也许 iOS 应用程序需要知道一个特定的手表才能将其发送到,尽管我只有一个手表配对。有没有人对可能发生的变化以及如何正确使用 transferUserInfo
有任何想法?
我想我现在可以正常工作了。首先,我必须将新的 WCSessionDelegate 方法添加到我的 iOS app:
@available(iOS 9.3, *)
func session(session: WCSession, activationDidCompleteWithState activationState: WCSessionActivationState, error: NSError?) {
if activationState == WCSessionActivationState.Activated {
NSLog("Activated")
}
if activationState == WCSessionActivationState.Inactive {
NSLog("Inactive")
}
if activationState == WCSessionActivationState.NotActivated {
NSLog("NotActivated")
}
}
func sessionDidBecomeInactive(session: WCSession) {
NSLog("sessionDidBecomeInactive")
}
func sessionDidDeactivate(session: WCSession) {
NSLog("sessionDidDeactivate")
// Begin the activation process for the new Apple Watch.
self.session.activateSession()
}
与我的手表OS应用类似:
@available(watchOSApplicationExtension 2.2, *)
func session(session: WCSession, activationDidCompleteWithState activationState: WCSessionActivationState, error: NSError?) {
if activationState == WCSessionActivationState.Activated {
NSLog("Activated")
}
if activationState == WCSessionActivationState.Inactive {
NSLog("Inactive")
}
if activationState == WCSessionActivationState.NotActivated {
NSLog("NotActivated")
}
}
但是 transferUserInfo 仍然对我不起作用,特别是当 Apple Watch 的屏幕关闭时。下面是我在 iPhone 和 Apple Watch 之间发送信息的方式 iOS 9.2/watchOS 2.1:
func tryWatchSendMessage(message: [String : AnyObject]) {
if self.session != nil && self.session.paired && self.session.watchAppInstalled {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
}
}
我假设在手表屏幕关闭时从 iPhone 向 Apple Watch 发送消息会导致 transferUserInfo 失败,因为它在 sendMessage 的错误处理程序中。当屏幕打开时,sendMessage 也按预期工作。但是,如果您的手表屏幕关闭,看起来 sendMessage 的错误回复处理程序并不总是被调用,即使请求失败也是如此。这与以前的 OS 版本不同。这似乎也造成了级联效应,即即使条件合适,后续消息也会失败。这就是让我相信 transferUserInfo 是罪魁祸首的原因。
我发现为了让我的消息可靠地传递,我需要同时检查 reachable 和 activationState。由于我还想继续支持早期的 iOS 和 watchOS 版本,因此我的 tryWatchSendMessage 方法变成了以下内容:
func tryWatchSendMessage(message: [String : AnyObject]) {
if #available(iOS 9.3, *) {
if self.session != nil && self.session.paired && self.session.watchAppInstalled && self.session.activationState == .Activated {
if self.session.reachable == true {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
} else {
self.session.transferUserInfo(message)
}
}
} else {
// Fallback on earlier versions
if self.session != nil && self.session.paired && self.session.watchAppInstalled {
if self.session.reachable == true {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
} else {
self.session.transferUserInfo(message)
}
}
}
}
进行这些更改似乎解决了我遇到的问题。我很想知道这些是否有助于解决其他人的问题,或者是否仍然存在与 transferUserInfo 不工作相关的问题。
自上周 2.2 更新以来,我在让通信正常工作方面遇到了非常相似的问题 - 但对我来说,我无法让应用程序上下文或文件传输过来。
和其他人一样,它在模拟器中有效,但在设备上无效。
我今天注意到我试图从后台线程发送数据 - 我将所有调用都包装在一个 dispatch_async(dispatch_get_main_queue())
中,突然间一切正常了。
我有一个现有的 iOS 9.2 和 watchOS 2.1 应用程序,它使用 sendMessage
和 transferUserInfo
将数据从 iPhone 发送到 Apple Watch。如果 sendMessage
失败,我正在使用 transferUserInfo
将数据排队等待稍后交付:
// *** In the iOS app ***
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
// *** In the watchOS app ***
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
// Handle message here
}
func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
// Handle message here
}
在不更改任何代码的情况下,运行 iOS 9.3 上的应用程序在真实设备上使用 watchOS 2.2(模拟器没有相同的问题),sendMessage
将数据传送到Apple Watch 只要手表在范围内并且屏幕打开。这是预期的,也是它以前的工作方式。但是,如果屏幕关闭并且 sendMessage
失败,当屏幕重新打开时 transferUserInfo
不再向 Apple Watch 传输数据。
为了找出出错的地方,我添加了以下 WCSessionDelegate
方法来查看 iOS 应用程序是否无法发送数据:
func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: NSError?) {
// Called when self.session.transferUserInfo completes
}
调用 transferUserInfo
后确实会调用此方法,但没有返回任何错误,iOS 应用程序似乎表明传输成功。
一开始我以为可能传输数据的时间变长了,但是放了一天数据还是没有传输。我现在有点怀疑它与新的多手表 API 有关,也许 iOS 应用程序需要知道一个特定的手表才能将其发送到,尽管我只有一个手表配对。有没有人对可能发生的变化以及如何正确使用 transferUserInfo
有任何想法?
我想我现在可以正常工作了。首先,我必须将新的 WCSessionDelegate 方法添加到我的 iOS app:
@available(iOS 9.3, *)
func session(session: WCSession, activationDidCompleteWithState activationState: WCSessionActivationState, error: NSError?) {
if activationState == WCSessionActivationState.Activated {
NSLog("Activated")
}
if activationState == WCSessionActivationState.Inactive {
NSLog("Inactive")
}
if activationState == WCSessionActivationState.NotActivated {
NSLog("NotActivated")
}
}
func sessionDidBecomeInactive(session: WCSession) {
NSLog("sessionDidBecomeInactive")
}
func sessionDidDeactivate(session: WCSession) {
NSLog("sessionDidDeactivate")
// Begin the activation process for the new Apple Watch.
self.session.activateSession()
}
与我的手表OS应用类似:
@available(watchOSApplicationExtension 2.2, *)
func session(session: WCSession, activationDidCompleteWithState activationState: WCSessionActivationState, error: NSError?) {
if activationState == WCSessionActivationState.Activated {
NSLog("Activated")
}
if activationState == WCSessionActivationState.Inactive {
NSLog("Inactive")
}
if activationState == WCSessionActivationState.NotActivated {
NSLog("NotActivated")
}
}
但是 transferUserInfo 仍然对我不起作用,特别是当 Apple Watch 的屏幕关闭时。下面是我在 iPhone 和 Apple Watch 之间发送信息的方式 iOS 9.2/watchOS 2.1:
func tryWatchSendMessage(message: [String : AnyObject]) {
if self.session != nil && self.session.paired && self.session.watchAppInstalled {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
}
}
我假设在手表屏幕关闭时从 iPhone 向 Apple Watch 发送消息会导致 transferUserInfo 失败,因为它在 sendMessage 的错误处理程序中。当屏幕打开时,sendMessage 也按预期工作。但是,如果您的手表屏幕关闭,看起来 sendMessage 的错误回复处理程序并不总是被调用,即使请求失败也是如此。这与以前的 OS 版本不同。这似乎也造成了级联效应,即即使条件合适,后续消息也会失败。这就是让我相信 transferUserInfo 是罪魁祸首的原因。
我发现为了让我的消息可靠地传递,我需要同时检查 reachable 和 activationState。由于我还想继续支持早期的 iOS 和 watchOS 版本,因此我的 tryWatchSendMessage 方法变成了以下内容:
func tryWatchSendMessage(message: [String : AnyObject]) {
if #available(iOS 9.3, *) {
if self.session != nil && self.session.paired && self.session.watchAppInstalled && self.session.activationState == .Activated {
if self.session.reachable == true {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
} else {
self.session.transferUserInfo(message)
}
}
} else {
// Fallback on earlier versions
if self.session != nil && self.session.paired && self.session.watchAppInstalled {
if self.session.reachable == true {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
} else {
self.session.transferUserInfo(message)
}
}
}
}
进行这些更改似乎解决了我遇到的问题。我很想知道这些是否有助于解决其他人的问题,或者是否仍然存在与 transferUserInfo 不工作相关的问题。
自上周 2.2 更新以来,我在让通信正常工作方面遇到了非常相似的问题 - 但对我来说,我无法让应用程序上下文或文件传输过来。
和其他人一样,它在模拟器中有效,但在设备上无效。
我今天注意到我试图从后台线程发送数据 - 我将所有调用都包装在一个 dispatch_async(dispatch_get_main_queue())
中,突然间一切正常了。