这一点非常重要,因为 Apple Watch 为 iOS 设备上运行的主应用程序提供了第二个屏幕/外围免费体验——无论是远程控制,还是快速查看/浏览大局中发生的事情。
在 上一篇文章 中,我展示了如何使用 IBM MobileFirst Platform Foundation 服务器在 Apple Watch 应用程序中设置远程日志记录和检测/分析。我使用下面描述的方法在上一篇文章的示例应用程序中的 WatchKit 和主机应用程序之间进行通信。
当我们谈论双向通信时,我们谈论的是通过两种方式发送数据:
- 将数据从主机应用程序发送到 WatchKit 应用程序
- 从主机应用向 WatchKit 应用发送数据
乍一看,您可能会想“哦,这很简单,只需使用 NSNotificationCenter 在应用程序的各个类之间进行通信”,但事情并没有那么简单。
Apple Watch 应用程序实际上由 3 个部分组成:1) 主要的 iOS 应用程序二进制文件,2) Apple Watch 上的用户界面,以及 3) WatchKit 扩展二进制文件(在 iOS 设备上)。
Apple Watch App – 架构组件
是的,你没看错,WatchKit 扩展(控制 Apple Watch UI 内部的所有逻辑并驻留在 iOS 设备上)是一个独立于“主”iOS 应用程序二进制文件的二进制文件。这些是独立的进程,因此主应用内存中的对象与扩展内存中的对象不同,因此这些进程不直接通信。 NSNotificationCenter 不会工作。
但是,您肯定有办法让这种场景发挥作用。
首先,WatchKit 具有从 WatchKit 扩展调用主机应用程序上的操作的方法。 WatchKit 的 openParentApplication 或 handleWatchKitExtensionRequest 方法都提供了在包含应用程序中调用操作和传递数据的能力,并提供了一种机制来在主机应用程序中的代码完成后调用 WatchKit 扩展中的“回复”代码块。
例如, 在 WatchKit 扩展中 ,这将调用主机应用程序中的操作并处理回复:
[WKInterfaceController openParentApplication:@{@"action":@"toggleStatus"} reply:^(NSDictionary *replyInfo, NSError *error) {
[logger trace:@"toggleStatus reply"];
[self updateUIFromHost:replyInfo];
}];
在主机应用程序中, 我们可以访问传递的 userInfo NSDictionary,我们可以相应地对其做出响应。例如,在下面的代码中,我在 userInfo 实例上设置了一个字符串值,并根据该字符串的值采取适当的操作。
[WKInterfaceController openParentApplication:@{@"action":@"toggleStatus"} reply:^(NSDictionary *replyInfo, NSError *error) {
[logger trace:@"toggleStatus reply"];
[self updateUIFromHost:replyInfo];
}];
这涵盖了“拉”场景,如果你想从你的 WatchKit 扩展调用你的主机应用程序中的操作,然后在 WatchKit 扩展中处理返回的响应以相应地更新你的 Apple Watch UI,这是很好的。
“推”场景呢?前面的场景仅涵盖源自 WatchKit 扩展内部的请求。如果你有一个进程在你的主机应用程序中运行,并且有更新你想在没有原始请求的情况下推送到 WatchKit 扩展,会发生什么?
没有共享内存,也不是共享进程,所以无论是 NSNotificationCenter 还是直接调用方法都行不通。但是,您*可以*使用 Darwin 通知(通过使用 CFNotificationCenter 在不同的进程中工作)。这支持跨进程的近实时交互,并且您可以在进程之间共享数据作为基于 CFdictionary 对象的属性。您还可以使用 访问组 共享大量数据,并使用 CFNotificationCenter 实现通知单独的进程。
注意:CFNotificationCenter 是 C 语法,不是 Objective-C 语法。
首先,您需要订阅 WatchKitExtension 中的 通知。注意静态 id 实例“staticSelf”……您稍后在从 C 通知回调调用 Objective-C 方法时将需要它。
[WKInterfaceController openParentApplication:@{@"action":@"toggleStatus"} reply:^(NSDictionary *replyInfo, NSError *error) {
[logger trace:@"toggleStatus reply"];
[self updateUIFromHost:replyInfo];
}];
在您的主机应用程序中, 您可以调用 CFNotificationCenterPostNotification 来调用 Darwin 通知。
[WKInterfaceController openParentApplication:@{@"action":@"toggleStatus"} reply:^(NSDictionary *replyInfo, NSError *error) {
[logger trace:@"toggleStatus reply"];
[self updateUIFromHost:replyInfo];
}];
然后 在 WatchKit 扩展中 ,处理通知,并相应地更新您的 WatchKit 扩展。
[WKInterfaceController openParentApplication:@{@"action":@"toggleStatus"} reply:^(NSDictionary *replyInfo, NSError *error) {
[logger trace:@"toggleStatus reply"];
[self updateUIFromHost:replyInfo];
}];
我们现在已经介绍了您可以在主机应用程序中*从* WatchKit 扩展请求数据或操作的场景,以及如何将数据从主机应用程序推送到 WatchKit 扩展。
现在,如果有一个库封装了其中的一些内容,并使开发人员更容易使用呢?当我在上一篇文章中编写应用程序时,我使用了上述方法。然而,我最近偶然发现了开源 MMWormhole ,它包装了 Darwin Notifications 方法(上图)以便于使用。我很确定我会在我的下一个 WatchKit 应用程序中使用它。