WatchOS2 WCSession sendMessage 不会在后台唤醒 iPhone
WatchOS2 WCSession sendMessage doesn't wake iPhone on background
这正在模拟器和真实物理设备上进行测试 iphone5s。我尝试使用 WCSession sendMessage 从 WatchOS2 扩展到 iPhone iOS9 代码进行通信。当 iphone 应用程序处于 运行 时,无论是在前台还是后台模式下,它都能很好地工作。
但是如果我终止 iPhone 应用程序(根本不是 运行 应用程序),那么我总是会遇到 errorHandler 超时。因此 Watch 无法再与 iPhone 通信。
"Error Domain=WCErrorDomain Code=7012 "Message reply took too long."
UserInfo={NSLocalizedDescription=Message reply took too long.,
NSLocalizedFailureReason=Reply timeout occured.}".
我认为它应该在后台唤醒 iPhone 应用程序。
知道如何解决或修复此问题吗?谢谢!
好吧,您可以使用 transferUserInfo
来对呼叫进行排队。使用 sendMessage
会在应用程序被杀死时导致错误
激活 AppDelegate
didFinishLaunchingWithOptions
方法中的 WCSession
很重要。您还必须在那里设置 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 应用中:
相同的会话设置,但这次还设置了委托:
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 收到数据,但这个例子肯定会唤醒应用程序。
经过数小时的尝试和@jeron 的提示。我终于自己弄清楚了问题。
在我的 session:didReceiveMessage 委托方法中,我有两个调用。 1.replyHandler打电话。 2. 在我的案例中,我有一个异步进程 运行 (RXPromise),它嵌套了很多 RXPromise 回调以从云服务中获取各种数据。我没有注意它,因为它应该立即调用 return。但是现在我把 RXPromise 块全部注释掉了,它每次都可以在后台唤醒 iOS 应用程序。
最后我弄清楚问题是因为在 RXPromise 调用之后,不再保证返回主线程。而且我相信 session:didReceiveMessage 必须是 return 在主线程上。我没有在 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.....
});
}
这正在模拟器和真实物理设备上进行测试 iphone5s。我尝试使用 WCSession sendMessage 从 WatchOS2 扩展到 iPhone iOS9 代码进行通信。当 iphone 应用程序处于 运行 时,无论是在前台还是后台模式下,它都能很好地工作。
但是如果我终止 iPhone 应用程序(根本不是 运行 应用程序),那么我总是会遇到 errorHandler 超时。因此 Watch 无法再与 iPhone 通信。
"Error Domain=WCErrorDomain Code=7012 "Message reply took too long." UserInfo={NSLocalizedDescription=Message reply took too long., NSLocalizedFailureReason=Reply timeout occured.}".
我认为它应该在后台唤醒 iPhone 应用程序。
知道如何解决或修复此问题吗?谢谢!
好吧,您可以使用 transferUserInfo
来对呼叫进行排队。使用 sendMessage
会在应用程序被杀死时导致错误
激活 AppDelegate
didFinishLaunchingWithOptions
方法中的 WCSession
很重要。您还必须在那里设置 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 应用中:
相同的会话设置,但这次还设置了委托:
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 收到数据,但这个例子肯定会唤醒应用程序。
经过数小时的尝试和@jeron 的提示。我终于自己弄清楚了问题。
在我的 session:didReceiveMessage 委托方法中,我有两个调用。 1.replyHandler打电话。 2. 在我的案例中,我有一个异步进程 运行 (RXPromise),它嵌套了很多 RXPromise 回调以从云服务中获取各种数据。我没有注意它,因为它应该立即调用 return。但是现在我把 RXPromise 块全部注释掉了,它每次都可以在后台唤醒 iOS 应用程序。
最后我弄清楚问题是因为在 RXPromise 调用之后,不再保证返回主线程。而且我相信 session:didReceiveMessage 必须是 return 在主线程上。我没有在 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.....
});
}