9

I have an existing iOS 9.2 and watchOS 2.1 app that uses sendMessage and transferUserInfo to send data from the iPhone to the Apple Watch. If sendMessage fails, I am using transferUserInfo to queue the data for later delivery:

// *** 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
}

Without changing any code and running the app on iOS 9.3 with watchOS 2.2 on a real device (simulator does not have the same problem), sendMessage delivers data to the Apple Watch as long as the watch is within range and the screen is on. This is as expected and how it previously worked. However, if the screen is off and sendMessage fails, transferUserInfo no longer delivers data to the Apple Watch when the screen turns back on.

In an attempt to find where this was erroring out, I added the following WCSessionDelegate method to see if the iOS app was failing to send the data:

func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: NSError?) {
    // Called when self.session.transferUserInfo completes
}

This method does get invoked after transferUserInfo is called, but there is no error returned and the iOS app seems to indicate that the transfer occurred successfully.

At first I thought that perhaps the time it takes to transfer the data has been increased, but after leaving the device alone for a day the data still had not transferred. I am now somewhat suspicious it has something to do with the new multi-watch API, and perhaps the iOS app needs to know a specific watch to send it to, though I only have ever had a single watch paired. Does anyone have any ideas on what might have changed and how to correctly use transferUserInfo?

4

2 回答 2

3

我想我现在有这个工作。首先,我必须将新的 WCSessionDelegate 方法添加到我的 iOS 应用程序中:

@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()
}

与我的 watchOS 应用程序类似:

@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 的屏幕关闭时。下面是我在 iOS 9.2/watchOS 2.1 中在 iPhone 和 Apple Watch 之间发送信息的方式:

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 的错误回复处理程序也不会总是被调用。这是与以前的操作系统版本不同的行为。这似乎也导致了级联效应,即使条件合适,后续消息也会失败。这就是让我相信 transferUserInfo 是罪魁祸首的原因。

我发现为了让我的消息可靠地通过,我需要同时检查reachable 和activationState。由于我还想继续支持早期的 iO​​S 和 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 无法正常工作相关的问题。

于 2016-03-30T20:08:36.810 回答
0

自上周更新 2.2 以来,我在让通信正常工作方面遇到了非常相似的问题 - 但对我来说,我无法获取应用程序上下文或文件来传输。

像其他人一样,它在模拟器上工作,但在设备上却不行。

我今天注意到我试图从后台线程发送数据 - 我将所有调用都包含在 a 中dispatch_async(dispatch_get_main_queue()),突然间一切正常。

于 2016-04-04T20:16:30.253 回答