webentwicklung-frage-antwort-db.com.de

iOS 10 UNUserNotificationCenterDelegate wird nicht aufgerufen. Push-Benachrichtigungen funktionieren nicht

Mir die Haare aus dem Kopf reißen, damit Push-Benachrichtigungen in iOS 10 funktionieren. Aktuelles Setup:

in 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")
        }

In 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)

Ich habe überprüft, ob das Token korrekt in das Backend hochgeladen wurde und es stimmt tatsächlich überein.

Ich habe auch implementiert:

    @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")
    }

Ich habe die Berechtigungen für alle Ziele festgelegt und Push aktiviert:

 enter image description here

Wenn ich jetzt versuche, eine Nachricht vom Backend zu senden, empfängt das Gerät einfach nichts. Delegierte werden nicht angerufen. Habe keine Ahnung was ich hier falsch mache. Push funktioniert für iOS9- und Android-Geräte. Gibt es Hinweise darauf, was ich falsch machen könnte?

18
Kex

Diese Antwort bezieht sich auf iOS 10+ unter Verwendung des Frameworks UserNotifications.

Sie benötigen eine Klasse, die dem Protokoll UNUserNotificationCenterDelegate entspricht. Es spielt keine Rolle, ob Sie nur dafür eine neue Klasse erstellen oder zu Ihrer Klasse AppDelegate hinzufügen. Ich würde jedoch empfehlen, eine eigene Klasse zu erstellen. Für die Beantwortung dieser Frage nehmen wir an, dass Sie eine UserNotificationController -Klasse dafür erstellen.

Die Klasse kann die folgenden Methoden haben:

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)

Dann müssen Sie in Ihrer AppDelegate.application(_:didFinishLaunchingWithOptions:) -Methode das delegate für das UNUserNotificationCenter.current() -Objekt auf eine Instanz Ihrer UserNotificationController -Klasse setzen. Möglicherweise möchten Sie eine gemeinsam genutzte Instanz verwenden.

Fordern Sie die Autorisierung des Benutzers an, um Benachrichtigungen mit der Methode UNUserNotificationCenter.requestAuthorization(options:completionHandler:) zu aktivieren, und überprüfen Sie im Feld completionHandler den Wert granted. Wenn true, registrieren Sie sich für Remote-Benachrichtigungen, indem Sie UIApplication.shared.registerForRemoteNotifications() aufrufen.

Wenn die App eine Push-Benachrichtigung erhält, können verschiedene Situationen auftreten. Ich werde versuchen, die häufigsten Fälle hier aufzulisten.

Lokale Benachrichtigungen:

Befindet sich die App im Vordergrund, ruft die App UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:) auf.

Befindet sich die App im Hintergrund (läuft oder nicht), wird nichts aufgerufen, bis der Benutzer auf die Benachrichtigung tippt. Zu diesem Zeitpunkt wird die App geöffnet und ruft UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:) auf.

Remote Notifications:

Der Inhalt der Nutzlast beeinflusst, was passiert. Es gibt drei Fälle für die Nutzlast: a) Nur die normalen Optionen alert, badge und sound b) Einschließlich der Option content-available (auf 1 oder true) c) einschließlich der Option mutable-content (festgelegt auf 1 oder true). Außerdem gibt es technisch d) wo Sie sowohl content-available als auch mutable-content haben, aber das löst nur beide Fälle aus.

Für a) nur alert, sound, badge info:

Dies funktioniert genauso wie eine lokale Benachrichtigung.

Für b) content-available == true:

Befindet sich die App im Vordergrund, wird UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:) aufgerufen.

Befindet sich die App im Hintergrund (läuft oder nicht), wird AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:) aufgerufen und nicht eine der Methoden in Ihrer Klasse UserNotificationController.

Für c) mutable-content == true:

Wenn Sie Ihrer Anwendung ein UNNotificationServiceExtension hinzugefügt haben, wird die Benachrichtigung verarbeitet und der Inhalt kann geändert werden. Dies geschieht unabhängig vom Status Ihrer Hauptanwendung. Wenn der Benutzer auf die (optional geänderte) Benachrichtigung tippt, wird diese wie eine lokale Benachrichtigung behandelt.

Ohne UNNotificationServiceExtension wird die Benachrichtigung wie eine normale Remote-Benachrichtigung behandelt.

Zusätzliche Hinweise:

Wenn Sie mutable-content verwenden, müssen Sie alert -Informationen in die Nutzlast aufnehmen. Andernfalls behandelt das System diese als unveränderlich und ruft nicht Ihre UNNotificationServiceExtension auf. Ihre geänderte Benachrichtigung muss weiterhin alert info enthalten, oder die ursprüngliche Benachrichtigungsnutzlast wird verwendet. Leider gibt es keine Möglichkeit zu verhindern, dass die Benachrichtigung dem Benutzer angezeigt wird.

Wenn der Benutzer bei Verwendung von content-available die App bei der letzten Verwendung erzwingt, startet er die App nicht neu und ruft AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:) nicht auf. Es wird zwar immer noch ein Alarm angezeigt, es wird jedoch der Ton abgespielt und das Abzeichen wie in der Nutzlast angegeben aktualisiert.

41
Dave Wood

Versuchen Sie, dass Ihre AppDelegate-Klasse das UNUserNotificationCenterDelegate-Protokoll anstelle einer separaten Klasse implementiert, die das Protokoll implementiert.

Ich hatte eine separate Klasse für den Delegierten und es hat nicht funktioniert. So sah mein Code aus, als ich ihn funktionierte:

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
17
PO Bengtsson

Stellen Sie sicher, dass Sie den AppDelegate für den UNUserNotificationCenter-Delegaten verwenden und den Delegaten beim Start in der application:didFinishLaunchingWithOptions - Methode festlegen. Denken Sie auch daran, UserNotifications und UserNotificationsUI.

0
Lee Probert

Ich hatte einen ganzen Tag damit zu kämpfen. Manchmal erhielt ich Benachrichtigungen, manchmal nicht, aber ich konnte niemals den Aufruf von userNotificationCenter(_:willPresent:completionHandler:) auslösen. 

Es stellte sich heraus, dass es zwei Probleme gab. Das erste bin ich immer noch etwas verwirrt: Meine Ziel-Implementierungsversion war auf 11.0 gesetzt, mein Projekt jedoch auf 10.0. Das Ändern des Projekts auf 11.0 war der erste Schritt. Ich verstehe das nicht ganz, aber vielleicht gibt es Unterschiede in der Benachrichtigungsverarbeitung zwischen 10.0 und 11.0?

Der zweite Teil war der Benachrichtigungscenter-Delegierte. Ich habe Apple Hinweis in den Dokumenten bemerkt : -

Wichtig

Sie müssen Ihr Delegatenobjekt dem UNUserNotificationCenter .__ zuweisen. Objekt vor dem Start der App. In einer iOS-App beispielsweise Sie müssen es in der .__ zuweisen. application (: willFinishLaunchingWithOptions :) oder application (: didFinishLaunchingWithOptions :) der Methode Ihrer Anwendung delegieren. Nach dem Aufruf dieser Methoden kann ein Delegat zugewiesen werden. Verpassen Sie eingehende Benachrichtigungen.

Ich hatte eine separate "Benachrichtigungs-Manager" -Klasse eingerichtet, in der sich auch die Rückrufe befanden (als Delegate-Protokollimplementierungen). Ich hatte dies als Instanzvariable in meinem App-Delegierten instanziiert, vorausgesetzt, dass dies zu einem frühen Zeitpunkt erstellt würde und kein Problem verursacht.

Ich habe eine Weile mit der Instantiierung usw. herumgespielt, aber nur, wenn ich den Delegat in meiner application(_:didFinishLaunchingWithOptions:)-Methode eingestellt und die Delegat-Callbacks im App-Delegierten implementiert habe. Ich habe es geschafft, das Problem zu beheben.

Mein Code wurde also im Wesentlichen: -

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()
    }
}
0
Echelon

Möglicherweise nicht die IntIdentifiers der UNNotificationCategory festlegen, wenn der Code wie folgt lautet:

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

es werden nicht die Delegate-Methoden von UNUserNotificationCenter aufgerufen.

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