如何观察来自不同应用程序的通知?

How to observe notifications from a different application?

我希望在某个应用程序触发事件时收到通知。我不是 Objective-C 开发人员,也不了解 OS X API——所以我希望这个问题不要太基础。

我的目标是将当前播放歌曲的元信息写入日志文件。对于 iTunes,我使用以下 Objective-C 行:

[[NSDistributedNotificationCenter defaultCenter]
 addObserver: myObserver selector: @selector(observeNotification:)
 name: @"com.apple.iTunes.playerInfo" object:nil];

但是,我也需要这个用于 AirServer(它是一个软件 AirPlay 接收器)。不幸的是,以下方法不起作用——观察者永远不会被调用:

[[NSDistributedNotificationCenter defaultCenter]
 addObserver: myObserver selector: @selector(observeNotification:)
 name: @"com.pratikkumar.airserver-mac" object:nil];

显然,AirServer 不会发送此类通知。但是,当一首新歌开始播放时,通知中心会有一个通知。

我的下一步是定期检查 OS X 通知中心的新通知(如此处所述:)。虽然这不太干净——所以我的问题是:在这种特殊情况下还有其他选择吗?

Catalina silently changed the addObserver behavior - you can no longer use a nil value for the name to observe all notifications - you have to pass in a name. This makes discovery of event names more difficult.

首先,你要明白,虽然NSDistributedNotificationCenter里面有Notification这个词;这没有关系。从 About Local Notifications and Remote Notifications,它确实声明:

Note: Remote notifications and local notifications are not related to broadcast notifications (NSNotificationCenter) or key-value observing notifications.

所以,在这一点上,我将从 NSDistributedNotificationCenter 的角度回答,而不是 Remote/Local 通知 - 你已经在链接的答案中找到了一个潜在的解决方案以供观察以这种方式包含通知记录的数据库文件。

由于 API 行为更改

,此示例代码不适用于 Catalina (10.15)

您需要做的第一件事是收听正确的通知。创建一个简单的应用程序来监听所有事件;例如使用:

NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self
           selector:@selector(notificationEvent:)
               name:nil
             object:nil];


-(void)notificationEvent:(NSNotification *)notif {
    NSLog(@"%@", notif);
}

表示通知是:

__CFNotification 0x6100000464b0 {name = com.airserverapp.AudioDidStart; object = com.pratikkumar.airserver-mac; userInfo = {
    ip = "2002:d55e:dbb2:1:10e0:1bfb:4e81:b481";
    remote = YES;
}}
__CFNotification 0x618000042790 {name = com.airserverapp.AudioDidStop; object = com.pratikkumar.airserver-mac; userInfo = {
    ip = "2002:d55e:dbb2:1:10e0:1bfb:4e81:b481";
    remote = YES;
}}

这表示addObserver调用中的name参数应该是com.airserverapp.AudioDidStartcom.airserverapp.AudioDidStop.

您可以使用这样的代码来确定所有通知,这将允许您在需要特定观察者时添加相关观察者。这可能是观察此类通知的最简单方法。