【问题标题】:Mac OS X NSUserNotificationCenter notification get dismiss event/callbackMac OS X NSUserNotificationCenter 通知获取关闭事件/回调
【发布时间】:2014-02-02 08:17:29
【问题描述】:

在我们的应用中,我们以警报样式显示通知中心通知。

显示通知工作正常,当用户通过单击通知或单击操作按钮与通知交互时,我们会收到回调。

但是,我们有兴趣在用户单击通知中的其他按钮时获取回调或事件。我已经看到 MAC OS 在显示其可用更新对话框时会这样做。

请参阅此图片以了解有关 OS X 更新可用警报的说明:

我已经在互联网上搜索了这个,也浏览了通知中心的文档thisthis

是否有任何未记录的 API?还是一些用于检测点击其他(关闭)按钮的自定义机制?

【问题讨论】:

    标签: objective-c macos notifications nsusernotification nsusernotificationcenter


    【解决方案1】:

    虽然另一个(关闭)按钮显然意味着关闭通知,但无论其自定义标题可能指示什么,当用户通过单击关闭按钮关闭通知时,没有优雅的方式来获得通知。

    但是,您可以做的是监视默认用户通知中心的 deliveredNotifications 属性:只要通知还没有被解除,数组就会包含通知。一旦通知被解除,数组将不再包含它。

    这可以在 NSUserNotificationCenter 委托方法中实现,如下所示:

    - (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                       ^{
                           BOOL notificationStillPresent;
                           do {
                               notificationStillPresent = NO;
                               for (NSUserNotification *nox in [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]) {
                                   if ([nox.identifier isEqualToString:notification.identifier]) notificationStillPresent = YES;
                               }
                               if (notificationStillPresent) [NSThread sleepForTimeInterval:0.20f];
                           } while (notificationStillPresent);
                           dispatch_async(dispatch_get_main_queue(), ^{
                               [self notificationHandlerForNotification:notification];
                           });
                       });
    }
    

    此代码将每 200 毫秒检查一次通知是否仍然存在。一旦它消失了,-notificationHandler: 方法将在主线程上被调用,这只是一个任意的回调方法。

    在这个自定义的 -notificationHandler: 方法中,您可以检查是否为通知调用了 NSUserNotificationCenter 的 didActivateNotification: 委托方法。如果没有,用户很可能点击了通知的关闭按钮。

    但是,这不是故障安全的,因为用户也可能以其他方式关闭了通知,即没有点击关闭按钮。

    【讨论】:

    • 我会试试你的解决方案。但是,deliveredNotifications 属性是什么?你能链接到一些文档吗?这是无证的吗?我没有通过互联网找到。
    • 感谢您的帮助。我现在明白了,我尝试了你的解决方案。我现在也理解了 DeliveredNotifications 属性。现在什么是“标识符”?您是指一些自定义属性吗?我需要在这个对象上定义吗? XCode 说在对象 NSUserNotification 上找不到属性。抱歉,我对这个主题有点陌生。
    • 对不起,标识符属性是 OS X 10.9 中的新属性,文档中没有正确记录,请参阅类头文件。简而言之,它是一个 NSString 实例,您可以根据需要将其用作任意标识符。来自头文件:“此标识符用于唯一标识通知。使用与现有通知相同的标识符传递的通知将替换该通知,而不是显示新通知。”
    • 我无法让它工作。我更改了if 语句以在显示通知之前检查当前[[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications].count 是否大于[[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications].count。这种方式效果很好。谢谢!
    • @DanielStorm 但这并不能告诉您删除了哪个通知。
    【解决方案2】:

    在 Swift 3 中

    func userNotificationCenter(_ center: NSUserNotificationCenter, didDismissAlert notification: NSUserNotification) {
            print("dismissed")
        }
    

    这不是NSUserNotificationDelegate 的一部分,但可以完美运行

    【讨论】:

    • @CristiBăluță 如果您使用的是 swift >=4,请确保使用 @objc 注释;否则 Objective-C 运行时将无法看到您的委托方法
    【解决方案3】:

    在 Swift 2.3 中:

    func userNotificationCenter(center: NSUserNotificationCenter, didDeliverNotification notification: NSUserNotification) {
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
            var notificationStillPresent: Bool
            repeat {
                notificationStillPresent = false
                for nox in NSUserNotificationCenter.defaultUserNotificationCenter().deliveredNotifications {
                    if nox.identifier == notification.identifier {
                        notificationStillPresent = true
                        break
                    }
                }
    
                if notificationStillPresent {
                    let _ = NSThread.sleepForTimeInterval(0.20)
                }
            } while notificationStillPresent
    
            dispatch_async(dispatch_get_main_queue()) {
                self.notificationHandlerFor(notification)
            }
        }
    }
    

    PS:另请注意,这是检测dismiss事件的方式,可以在多种情况下触发。

    1. 点击otherButton 关闭
    2. 点击通知中心的Clear All按钮

    PS 2:如果你使用deliveryRepeatInterval,比如说1分钟,deliveredNotifications数组中有多个通知,而只显示一个。解雇将触发多个回调。

    PS 3:点击actionButton也会触发dismissal回调

    【讨论】:

    • 目前我试图区分单个通知被解雇(用户按下通知左上角的小 X)和“全部清除”操作(用户单击堆叠线程上的 X通知,然后在出现的“全部清除”上。没有用。我得到相同的 actionID - 以及线程中通知之一的任意响应+请求。击败我。
    【解决方案4】:

    这对我有帮助

    func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) {
        switch (notification.activationType) {
        case .none:
            print("none CLicked")
            break
        case .actionButtonClicked:
            print("Additional Action Clicked")
            break
        case .contentsClicked:
            print("contents CLicked")
            break
        case .replied:
            print("replied Action Clicked")
            break
        case .additionalActionClicked:
            print("Additional  MENU  Action Clicked")
            break
        }
    

    【讨论】:

      猜你喜欢
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 2012-01-19
      相关资源
      最近更新 更多