WatchOS2 WCSession sendMessage不会在后台唤醒iPhone

时间:2015-10-14 22:16:00

标签: ios watch-os-2

这是在模拟器和真实物理设备iphone5s上进行测试的。我尝试使用WCSession sendMessage从WatchOS2扩展到iPhone iOS9代码进行通信。当iphone应用程序在前台和后台模式下运行时,它运行良好。

但如果我杀了iPhone应用程序(根本没有运行应用程序),那么我总是得到errorHandler超时。所以Watch再也无法与iPhone通信了。

  

“Error Domain = WCErrorDomain Code = 7012”消息回复花了太长时间。“   UserInfo = {NSLocalizedDescription =邮件回复花了太长时间。,   NSLocalizedFailureReason =发生回复超时。}“。

我认为应该在后台唤醒iPhone应用程序。

知道如何解决这个问题或修复它?谢谢!

3 个答案:

答案 0 :(得分:16)

WCSession AppDelegate方法中激活didFinishLaunchingWithOptions非常重要。你还必须在那里设置WCSessionDelegate。如果您在其他地方执行此操作,则当系统在后台启动被杀应用程序时,可能无法执行代码。

此外,您应该通过replyHandler发送回复。如果你尝试发送其他东西,系统会等待永远不会发出的回复。因此超时错误。

以下是一个示例,如果它被杀死,它会唤醒应用程序:

在WatchExtension中:

设置会话。通常在您的ExtensionDelegate中:

func applicationDidFinishLaunching() {
    if WCSession.isSupported() {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

然后在需要应用内容时发送消息:

if WCSession.defaultSession().reachable {
    let messageDict = ["message": "hello iPhone!"]
    WCSession.defaultSession().sendMessage(messageDict, replyHandler: { (replyDict) -> Void in
        print(replyDict)
        }, errorHandler: { (error) -> Void in
        print(error)
    }
}

在iPhone App中:

相同的会话设置,但这次也设置了委托:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    ...
    if WCSession.isSupported() {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

然后实现委托方法将回复发送到手表:

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    replyHandler(["message": "Hello Watch!"])
}

只要Watch和iPhone之间存在连接,此功能就可以使用。如果应用程序未运行,系统将在后台启动它。

我不知道系统是否会等到你从iCloud收到你的数据,但是这个例子肯定会唤醒应用程序。

答案 1 :(得分:9)

经过几个小时的尝试并从@jeron提示。我终于弄明白了这个问题。

在我的会话中:didReceiveMessage委托方法,我有两个调用。 1.replyHandler电话。 2.在我的情况下我运行了一个异步进程(RXPromise),它嵌套了很多RXPromise回调来从云服务中获取各种数据。我没有注意它,因为它应该立即呼叫并返回。但是现在我已经将RXPromise块一起注释掉,它每次都可以在后台唤醒iOS应用程序。

最后我弄清楚麻烦是因为在RXPromise调用之后,再也不能保证退回到主线程了。我相信session:didReceiveMessage必须在主线程上返回。我在Apple文档的任何地方都没有看到这一点。

最终解决方案:

- (void)session:(WCSession *)session
    didReceiveMessage:(NSDictionary<NSString *, id> *)message
         replyHandler:(void (^)(NSDictionary<NSString *, id> *_Nonnull))replyHandler {

    replyHandler(@{ @"schedule" : @"OK" });

    dispatch_async(dispatch_get_main_queue(), ^{
      Nested RXPromise calls.....
    });

}

答案 2 :(得分:0)

好吧,您可以使用transferUserInfo来排队呼叫。使用sendMessage会在应用被杀时导致错误