在使用iOS 9.3的watchOS 2.2中,WCSession的transferUserInfo不再可靠地工作

时间:2016-03-29 13:58:10

标签: ios9 watchkit watch-os-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就会向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

有任何想法

2 个答案:

答案 0 :(得分: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的错误回复处理程序也不总是被调用。这与以前的OS版本不同。这似乎也引起了级联效应,即使条件合适,后续消息也会失败。这让我相信transferUserInfo应该受到责备。

我发现为了让我的消息可靠地通过,我需要检查可达和激活状态。由于我还想继续支持早期的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无关的问题。

答案 1 :(得分:0)

自上周2.2更新以来,我在沟通工作方面遇到了非常类似的问题 - 但对我来说,我无法获得应用程序上下文或文件转移。

和其他人一样,它在模拟器中工作,但在设备上却没有。

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