ios9 - WCSession 的 TransferUserInfo 不再可靠地在带有 iOS 9.3 的 watchOS 2.2 中工作

标签 ios9 watchkit watchos-2 wcsession ios9.3

我有一个现有的 iOS 9.2 和 watchOS 2.1 应用程序,它使用 sendMessagetransferUserInfo 将数据从 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
}

在不更改任何代码并在真实设备上使用 watchOS 2.2 的 iOS 9.3 上运行应用程序(模拟器没有相同问题)的情况下,sendMessage 只要 watch 有时间就会向 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 应用似乎表明传输成功。

起初我以为传输数据的时间可能增加了,但是将设备闲置一天后,数据仍然没有传输。我现在有点怀疑它与新的多 watch API 有关,也许 iOS 应用程序需要知道将其发送到的特定 watch ,尽管我只配对过一个 watch 。有谁对可能发生的变化以及如何正确使用 transferUserInfo 有任何想法吗?

最佳答案

我想我现在可以正常工作了。首先,我必须将新的 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)
        }
    }
}

我曾假设在 watch 屏幕关闭时从 iPhone 向 Apple Watch 发送消息会导致 transferUserInfo 失败,因为它位于 sendMessage 的错误处理程序中。当屏幕打开时,sendMessage 也按预期工作。但是,如果您的 watch 屏幕关闭,即使请求失败,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 不起作用相关的问题。

关于ios9 - WCSession 的 TransferUserInfo 不再可靠地在带有 iOS 9.3 的 watchOS 2.2 中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36286531/

相关文章:

ios - 启动后立即添加 View 时出现 "Application windows are expected to have a root view controller"消息,仅限 iOS 9

objective-c - 无法在 iOS9 中暂停 SKEmitterNode

ios - 使用基于页面的导航将数组数据从一个界面传递到 watchkit 中的另一个界面?

swift - iWatch : WKInterfaceLabel is it possible to stop text from being cut off with "..." at the end of a label?

objective-c - 保存到 watchOS 2 文档文件夹

未调用 iOS9 Safari 内容拦截器扩展

ios - 清理后,managedObjectContext 为 nil 并导致 fatal error : unexpectedly found nil while unwrapping an optional value

ios - WCSession 文件传输问题

ios - Apple Watch 通知负载

iOS/watchos2 - 为什么没有 session :didReceiveApplicationContext: fire?