Уведомление Mac OS X NSUserNotificationCenter об отклонении события/обратного вызова

В нашем приложении мы отображаем уведомления Центра уведомлений в стиле предупреждений.

Отображение уведомления работает нормально, а также мы получаем обратный вызов, когда пользователь взаимодействует с уведомлением, либо щелкнув уведомление, либо нажав кнопку «Действие».

Однако нас интересует получение обратного вызова или события, когда пользователь нажимает кнопку «Другое» в уведомлении. Я видел, как MAC OS делает это, когда отображает диалоговое окно доступных обновлений.

Обратитесь к этому изображению для получения разъяснений о доступном предупреждении об обновлении OS X:

введите здесь описание изображения

Я искал это в Интернете, а также просмотрел документацию Центра уведомлений это и это.

Есть ли недокументированный API? или какой-то специальный механизм для обнаружения нажатия кнопки «Другое (закрыть)»?




Ответы (4)


В то время как другая кнопка (закрыть) явно предназначена для закрытия уведомления, независимо от того, что может означать ее настраиваемый заголовок, нет элегантного способа получить уведомление, когда пользователь закрывает уведомление, нажав кнопку закрытия.

Однако вы можете отслеживать свойство 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: вы можете проверить, был ли вызван метод didActivateNotification: NSUserNotificationCenter для уведомления. Если это не так, пользователь, скорее всего, нажал кнопку закрытия уведомления.

Однако это не является отказоустойчивым, поскольку пользователь также мог закрыть уведомление иным образом, т. е. не нажимая кнопку закрытия.

person Tim    schedule 26.01.2014
comment
Я попробую ваше решение. Однако что такое свойство DeliverNotifications? Не могли бы вы дать ссылку на какую-нибудь документацию? Это недокументировано? в инете не нашел. - person URB; 27.01.2014
comment
Спасибо за вашу помощь. Теперь я получаю идею, и я попробовал ваше решение. Теперь я также понимаю свойство DeliverNotifications. Что такое идентификатор? Вы имеете в виду какое-то пользовательское свойство? что мне нужно определить на этом объекте? XCode говорит, что свойство не найдено в объекте NSUserNotification. Извините, но я немного новичок в этом вопросе. - person URB; 27.01.2014
comment
К сожалению, свойство идентификатора является новым в OS X 10.9, и оно не задокументировано должным образом в документах, см. файл заголовка класса. Короче говоря, это экземпляр NSString, который вы можете использовать для произвольного идентификатора, если хотите. Из заголовочного файла: этот идентификатор используется для уникальной идентификации уведомления. Уведомление, доставленное с тем же идентификатором, что и существующее уведомление, заменит это уведомление, а не отобразит новое. - person Tim; 28.01.2014
comment
При работе с OS X 10.8 вам придется использовать другой подход для сравнения уведомлений, например. через их свойство userInfo, где вы также можете хранить какой-то уникальный идентификатор, но общая идея остается прежней. - person Tim; 28.01.2014
comment
Хорошо, идея со словарем userInfo работает. Отметив это как ответ, так как это действительно дало мне идею реализовать решение. Спасибо. - person URB; 28.01.2014
comment
Кажется, лучше сравнивать уведомления с isEqual: if ([nox.identifier isEqual:notification])notificationStillPresent = YES; - person JasonZ; 24.03.2014
comment
Я не смог заставить это работать. Я изменил оператор if, чтобы проверить, больше ли текущий [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications].count, чем [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications].count перед отображением уведомления. Хорошо работает таким образом. Спасибо! - person Daniel Storm; 26.02.2016
comment
@DanielStorm Но это не говорит вам, какое уведомление было удалено. - person maxisme; 29.01.2017

В Свифт 3

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

Это не часть NSUserNotificationDelegate, но работает отлично

person vishal-android-freak    schedule 23.01.2017
comment
@CristiBăluță, если вы используете swift ›=4, убедитесь, что вы используете аннотацию @objc; в противном случае среда выполнения Objective-C не сможет увидеть ваш метод делегата - person Felix J. Acero; 16.05.2018

В Свифте 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: Также обратите внимание, что это способ обнаружения события отклонения, которое может быть вызвано в нескольких случаях.

  1. Нажмите otherButton, чтобы закрыть
  2. Нажмите кнопку Clear All в Центре уведомлений.

PS 2: Если вы используете deliveryRepeatInterval, скажем, 1 минуту, в массиве deliveredNotifications есть несколько уведомлений, а отображается только одно. Увольнение должно вызвать несколько обратных вызовов.

PS 3: Щелчок actionButton также вызовет обратный вызов увольнения

person Harry Ng    schedule 26.10.2016

Это помогло мне

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
    }
person Geet    schedule 19.01.2018