在没有手表应用程序请求的情况下通知WatchKit应用程序更新

And*_*vis 18 ios apple-watch watchkit

我知道手表应用程序打开父应用程序和发送/接收数据的功能WKInterfaceController openParentApplicationhandleWatchKitExtensionRequest方法.

但是如何...在用户使用父应用程序并在父应用程序中执行操作(即更改背景颜色)的实例中,如何立即通知监视应用程序并执行相关操作手表呢?

我相信MMWormhole在这个例子中就足够了,这是我应该采取的最佳方法还是有替代方案?

lvp*_*lvp 39

背景

首先,让我们总结一下我们所知道的.我们有

  • 在iPhone上运行的应用程序(我将其称为iPhone应用程序)
  • 在Watch上运行的app ...具体来说
    • 在Watch上运行的UI
    • 在iPhone上作为Extension运行的代码.

第一行和最后一行对我们来说最重要.是的,Extension通过您的iPhone应用程序发送到AppStore,但是这两件事可以在iOS操作系统中单独运行.因此,Extension和iPhone应用程序是两个不同的进程 - 在OS中运行的两个不同的程序.

因为这个事实,我们无法使用,[NSNotificationCenter defaultCenter]因为当您尝试NSLog()在iPhone上的defaultCenter和Extension中的defaultCenter时,它们将具有不同的内存地址.

达尔文来救援!

正如您可能想象的那样,这类问题对于开发人员来说并不陌生,它的正确用语是进程间通信.所以在OS X和iOS中有... Darwin Notification机制.最简单的方法是从CFNotificationCenter类中实现几个方法.

使用CFNotificationCenter时,您会发现它看起来与NSNotificationCenter非常相似.我的猜测是NSNotif ..是围绕CFNotif构建的......但我没有证实这个假设.现在,到了这一点.

因此,假设您想要从iPhone发送通知来回观看.我们应该做的第一件事是注册通知.

- (void)registerToNotification
{    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceivedNSNotification) name:@"com.example.MyAwesomeApp" object:nil];

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), didReceivedDarwinNotification, CFSTR("NOTIFICATION_TO_WATCH"), NULL, CFNotificationSuspensionBehaviorDrop);
}
Run Code Online (Sandbox Code Playgroud)

您可能想知道为什么我为NSNotificationCenter添加了观察者?为了完成我们的任务,我们需要创建一些循环,你马上就会看到它.

至于第二种方法.

CFNotificationCenterGetDarwinNotifyCenter() - 获得达尔文通知中心

(__bridge const void *)(self) - 通知观察员

didReceivedDarwinNotification - 当对象收到通知时触发的callBack方法.基本上它与@selectorNSNotification中的相同

CFSTR("NOTIFICATION_TO_WATCH") - 通知名称,NSNotification中的相同故事,但这里我们需要CFSTR方法将字符串转换为CFStringRef

最后最后的两个参数objectsuspensionBehaviour-无论是当我们使用DarwinNotifyCenter忽略.

很酷,所以我们注册为观察员.因此,让我们实现我们的回调方法(其中有两个,一个用于CFNotificationCenter,另一个用于NSNotificationCenter).

void didReceivedDarwinNotification()
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"com.example.MyAwesomeApp" object:nil];
}
Run Code Online (Sandbox Code Playgroud)

现在,如您所见,此方法不会以此开头- (void)Name....为什么?因为它是C方法.你知道我们为什么需要NSNotificationCenter吗?从C方法我们无权访问self.一个选项是声明自己的静态指针,如下所示:static id staticSelf分配它staticSelf = self然后使用它didReceivedDarwinNotification:((YourClass*)staticSelf)->_yourProperty但我认为NSNotificationCenter是更好的方法.

那么在选择器中响应你的NSNotification:

- (void)didReceivedNSNotification
{
    // you can do what you want, Obj-C method
}
Run Code Online (Sandbox Code Playgroud)

当我们最终注册为观察者时,我们可以从iPhone应用程序发送一些东西.

为此,我们只需要一行代码.

CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("NOTIFICATION_TO_WATCH"), (__bridge const void *)(self), nil, TRUE);
Run Code Online (Sandbox Code Playgroud)

它可以在您的ViewController或Model中.

再次,我们想得到CFNotificationCenterGetDarwinNotifyCenter(),然后我们指定通知的名称,发布通知的对象,字典对象(使用DarwinNotifyCenter时忽略,最后一个参数是问题答案:立即交付?

以类似的方式,您可以从Watch向iPhone发送通知.从明显的原因我建议使用不同的通知名称,CFSTR("NOTIFICATION_TO_IPHONE")以避免例如iPhone向Watch发送通知和自身的情况.

总结一下

MMWormhole即使测试涵盖了大多数(如果不是全部)代码,也是完美的,写得很好的课程.它易于使用,只需记住之前设置您的AppGroups.但是,如果您不想将第三方代码导入项目,或者由于某些其他原因而不想使用它,则可以使用此答案中提供的实现.特别是如果你不想/需要在iPhone和Watch之间交换数据.

还有第二个好项目LLBSDMessaging.它基于伯克利插座.更复杂,基于更低级别的代码.这里链接到冗长但写得很好的博客文章,你会在那里找到Github的链接.http://ddeville.me/2015/02/interprocess-communication-on-ios-with-berkeley-sockets/.

希望这有帮助.

  • 这可能是我对SO提出的问题最有帮助的答案.谢谢! (2认同)
  • 那是一场精彩的演讲!也许我从这个概念派生的设计模式对其他人有用:我用它在Obj-C中创建一个NSObject类别"DarwinNotification",我可以在C中嵌入代码.Bridging-Header.h文件给出了我的Swift类从此类别访问方便的方法:registerToDarwinNotification,unregisterFromDarwinNotification,postDarwinNotification和didReceiveNSNotification.我的概念证明在第一次尝试时没有遇到任何麻烦.谢谢! (2认同)