WatchOS2 WCSession sendMessage不会在后台唤醒iPhone

Fra*_*ang 14 ios watchos-2

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

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

"错误域= WCErrorDomain代码= 7012"消息回复花了太长时间."UserInfo = {NSLocalizedDescription =消息回复花了太长时间.,NSLocalizedFailureReason =回复超时发生.}".

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

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

joe*_*ern 17

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

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

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

在WatchExtension中:

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

func applicationDidFinishLaunching() {
    if WCSession.isSupported() {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后当您需要应用程序中的某些内容时发送消息:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

在iPhone App中:

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

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

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

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

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

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


Fra*_*ang 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.....
    });

}
Run Code Online (Sandbox Code Playgroud)