IOS 10 UNUserNotificationCenterDelegate не вызывается. push notifications не работает

Разрывание связей с волосами, чтобы получить push-уведомления для работы в iOS10. Текущая настройка:

в func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool:

if #available(iOS 10.0, *) {

            let center = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in

                if error == nil {
                    print("DID REQUEST THE NOTIFICATION")
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
            print("DID SET DELEGATE")
        }

В func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data):

print("DID REGISTER FOR A REMOTE NOTIFICATION AND THE TOKEN IS \(deviceToken.base64EncodedString())"           
let request = UpdatePushNotificationSubscription_Request(deviceToken: deviceToken)
updatePushNotificationSubscriptionWorker.updateSubscription(request)

Я проверил, что токен правильно загружен на сервер и действительно соответствует.

Я также реализовал:

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        print("GOT A NOTIFICATION")

    }


    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

        //This is for the user tapping on the notification
        print("GOT A NOTIFICATION")
    }

Я установил права для всех целей и включил push:

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

Теперь, когда я пытаюсь отправить сообщение из бэкэнд, устройство просто ничего не получает. Делегаты не звонят. Не знаю, что я делаю неправильно здесь. Push работает для iOS9 и Android-устройств. Любые указания на то, что я могу сделать неправильно?

Ответ 1

Этот ответ относится к iOS 10+, используя инфраструктуру UserNotifications.

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

Класс может иметь следующие методы:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

optional func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)

Затем в вашем методе AppDelegate.application(_:didFinishLaunchingWithOptions:) вам нужно установить delegate в UNUserNotificationCenter.current() объект экземпляру вашего класса UserNotificationController. Вероятно, вы захотите использовать общий экземпляр.

Запросить авторизацию от пользователя для включения уведомлений с помощью метода UNUserNotificationCenter.requestAuthorization(options:completionHandler:), а в completionHandler - проверить значение granted. Если true, зарегистрируйтесь для удаленных уведомлений, вызвав UIApplication.shared.registerForRemoteNotifications().

Теперь, когда приложение получает push-уведомление, существует несколько различных ситуаций, которые могут произойти. Здесь я расскажу о наиболее распространенных случаях.

Локальные уведомления:

Если приложение находится на переднем плане, приложение вызовет UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:).

Если приложение находится в фоновом режиме (работает или нет), ничего не вызывается до тех пор, пока пользователь не удалит уведомление, в этот момент приложение откроется и вызовет UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:).

Удаленные уведомления:

Содержимое полезной нагрузки повлияет на то, что произойдет. Для полезной нагрузки три случая: a) только обычные опции alert, badge и sound b), включая опцию content-available (установленную в 1 или true) c) включая mutable-content (установлен на 1 или true). Плюс там технически d), где у вас есть как content-available, так и mutable-content, но это просто вызывает оба случая.

Для a) просто alert, sound, badge info:

Это работает так же, как локальное уведомление.

Для b) content-available == true:

Если приложение находится на переднем плане, вызывается UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:).

Если приложение находится в фоновом режиме (выполняется или нет), вызывается AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:), а не один из методов в вашем классе UserNotificationController.

Для c) mutable-content == true:

Если вы добавили в приложение UNNotificationServiceExtension, он обработает уведомление и может изменить содержимое. Это происходит независимо от состояния вашего основного приложения. Если (необязательно измененное) уведомление используется пользователем, оно обрабатывается как локальное уведомление выше.

Без UNNotificationServiceExtension уведомление обрабатывается как обычное удаленное уведомление выше.

Дополнительные примечания:

При использовании mutable-content вы должны включить alert информацию в полезную нагрузку, или система будет рассматривать ее как неизменяемую и не вызывать в ваш UNNotificationServiceExtension. Ваше измененное уведомление должно содержать информацию alert или использовать полезную нагрузку исходного уведомления. К сожалению, нет способа предотвратить появление уведомления у пользователя.

При использовании content-available, если пользователь принудительно закрыл приложение в последний раз, когда он его использовал, система не перезапустит приложение или не вызовет AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:). Хотя он все равно отобразит любое предупреждение, воспроизведет звук и обновит значок, как указано в полезной нагрузке.

Ответ 2

Попробуйте создать класс AppDelegate вместо UNUserNotificationCenterDelegate вместо отдельного класса, реализующего протокол.

У меня был отдельный класс для делегата, и он не работал. Так выглядел мой код, когда я получил его:

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application 

    UIApplication.shared.registerForRemoteNotifications()

    let center = UNUserNotificationCenter.current()
    center.delegate = self //DID NOT WORK WHEN self WAS MyOtherDelegateClass()

    center.requestAuthorization(options: [.alert, .sound, .badge]) {
        (granted, error) in
            // Enable or disable features based on authorization.
            if granted {
                // update application settings
            }
    }

    return true
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent: UNNotification,
                            withCompletionHandler: @escaping (UNNotificationPresentationOptions)->()) {
    withCompletionHandler([.alert, .sound, .badge])
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive: UNNotificationResponse,
                            withCompletionHandler: @escaping ()->()) {
    withCompletionHandler()
}

// and so forth for your other AppDelegate stuff

Ответ 3

Я боролся с этим целый день. Иногда я получал уведомления, иногда нет, но я никогда не мог вызвать обратный вызов userNotificationCenter(_:willPresent:completionHandler:).

Оказалось, были две проблемы. Первое, что меня все еще немного смущает: моя целевая версия развертывания была установлена на 11.0, но мой проект был установлен на 10.0. Изменение проекта на 11.0 было первым шагом. Я не до конца понимаю, но может быть есть какая-то разница в обработке уведомлений между 10.0 и 11.0?

Вторая часть была делегатом центра уведомлений. Я заметил заметку Apple в документации: -

Important

Вы должны назначить свой объект делегата в UNUserNotificationCenter объект, прежде чем ваше приложение завершает запуск. Например, в приложении для iOS Вы должны назначить его в application (: willFinishLaunchingWithOptions :) или application (: didFinishLaunchingWithOptions :) метод вашего приложения делегировать. Назначение делегата после вызова этих методов может Вы пропустите входящие уведомления.

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

Я некоторое время возился с созданием экземпляров и т.д., Но только когда я установил делегат в своем методе application(_:didFinishLaunchingWithOptions:) и реализовал обратные вызовы делегата в делегате приложения, мне удалось это исправить.

Таким образом, мой код стал, в основном: -

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    // You MUST do this HERE and nowhere else!
    UNUserNotificationCenter.current().delegate = self

    // other stuff

    return true
}

extension AppDelegate: UNUserNotificationCenterDelegate {

    // These delegate methods MUST live in App Delegate and nowhere else!

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        if let userInfo = notification.request.content.userInfo as? [String : AnyObject] {
        }
        completionHandler(.alert)
    }

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        if let userInfo = response.notification.request.content.userInfo as? [String : AnyObject] {
        }
        completionHandler()
    }
}

Ответ 4

Возможно, не установлен UNNotificationCategory intentIdentifiers, если код такой:

UNNotificationCategory* expiredCategory = [UNNotificationCategory
                                               categoryWithIdentifier:@"TIMER_EXPIRED"
                                               actions:@[snoozeAction, stopAction]
                                               intentIdentifiers:@[]
                                               options:UNNotificationCategoryOptionCustomDismissAction];

он не будет вызывать методы делегата UNUserNotificationCenter, поэтому вы должны установить intentIdentifiers следующим образом:

UNNotificationCategory* expiredCategory = [UNNotificationCategory
                                               categoryWithIdentifier:@"TIMER_EXPIRED"
                                               actions:@[snoozeAction, stopAction]
                                               intentIdentifiers:@[@"a",@"b"]
                                               options:UNNotificationCategoryOptionCustomDismissAction];

Ответ 5

Помимо того, что вы убедитесь, что вы используете AppDelegate для делегата UNUserNotificationCenter, и задаете делегат в методе application:didFinishLaunchingWithOptions при запуске, убедитесь, что вы также не забыли импортировать UserNotifications и UserNotificationsUI.