que developer apple ios swift apple-push-notifications

developer - iOS 10 UNUserNotificationCenterDelegate no se llama. notificaciones push no funcionan



apple developer (4)

Desgarrándome el pelo para que las notificaciones push funcionen en iOS10. Configuración actual:

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

En la 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)

He comprobado que el token se ha cargado correctamente en el backend y, de hecho, coincide.

También he implementado:

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

He establecido los derechos para todos los objetivos y habilitado la inserción:

Ahora, cuando intento enviar un mensaje desde el servidor, el dispositivo simplemente no recibe nada. Los delegados no están siendo llamados. No tengo idea de lo que estoy haciendo mal aquí. Push está trabajando para dispositivos iOS9 y Android. ¿Algún indicador de lo que podría estar haciendo mal?


Esta respuesta pertenece a iOS 10+, utilizando el marco de UserNotifications .

Necesita una clase para cumplir con el protocolo UNUserNotificationCenterDelegate . No importa si crea una nueva clase solo para esto, o si la agrega a su clase AppDelegate . Sin embargo, recomiendo crear una clase dedicada. Para los propósitos de esta respuesta, supongamos que creas una clase UserNotificationController para ella.

La clase puede tener los siguientes métodos:

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)

Luego, en su método AppDelegate.application(_:didFinishLaunchingWithOptions:) , debe establecer el delegate en el objeto UNUserNotificationCenter.current() en una instancia de su clase UserNotificationController . Probablemente querrás usar una instancia compartida.

Solicite la autorización del usuario para habilitar las notificaciones utilizando el UNUserNotificationCenter.requestAuthorization(options:completionHandler:) y, en el controlador de la cuenta completionHandler , verifique el valor granted . Si es true , regístrese para UIApplication.shared.registerForRemoteNotifications() notificaciones remotas llamando a UIApplication.shared.registerForRemoteNotifications() .

Ahora, cuando la aplicación recibe una notificación de inserción, hay varias situaciones diferentes que pueden suceder. Intentaré y enumeraré los casos más comunes aquí.

Notificaciones locales:

Si la aplicación está en primer plano, llamará a UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:) .

Si la aplicación está en segundo plano (ejecutándose o no), no se llama nada hasta que el usuario toque la notificación, en ese momento, la aplicación se abrirá y llamará a UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:) .

Notificaciones remotas:

El contenido de la carga útil afectará a lo que suceda. Hay tres casos para la carga útil, a) solo las opciones normales de alert , badge y sound b) que incluyen la opción de content-available (establecido en 1 o true ) c) que incluye la opción de mutable-content (establecido en 1 o true ) . Además, hay técnicamente d) donde tienes content-available y mutable-content , pero eso solo desencadena ambos casos.

Para a) solo alert , sound , información de badge :

Esto funciona igual que una notificación local.

Para b) content-available == true:

Si la aplicación está en primer plano, se UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:) .

Si la aplicación está en segundo plano, (en ejecución o no), se llama AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:) , no se llama uno de los métodos en su clase UserNotificationController .

Para c) mutable-content == verdadero:

Si ha agregado UNNotificationServiceExtension a su aplicación, manejará la notificación y podrá modificar el contenido. Esto sucede independientemente del estado de su aplicación principal. Si el usuario toca la notificación (opcionalmente modificada), entonces se maneja como una notificación local arriba.

Sin una UNNotificationServiceExtension notificación de UNNotificationServiceExtension , la notificación se trata como una notificación remota normal anterior.

Notas adicionales:

Cuando use mutable-content , debe incluir información de alert en la carga útil, o el sistema lo tratará como inmutable y no llamará a su UNNotificationServiceExtension . Su notificación modificada aún debe incluir información de alert , o se utilizará la carga de notificación original. Lamentablemente, no hay forma de evitar que la notificación se muestre al usuario.

Cuando use el content-available , si el usuario forzó el cierre de la aplicación la última vez que la usó, el sistema no la AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:) ni llamará a AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:) . Aunque seguirá mostrando cualquier alerta, reproducirá el sonido y actualizará la insignia como se indica en la carga útil.


Intente hacer que su clase AppDelegate implemente el protocolo UNUserNotificationCenterDelegate en lugar de una clase separada que implemente el protocolo.

Tuve una clase separada para el delegado y no funcionó. Así es como se veía mi código cuando lo puse en funcionamiento:

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


Luché con esto por un día completo. A veces recibía notificaciones, a veces no, pero nunca podía obtener el userNotificationCenter(_:willPresent:completionHandler:) del userNotificationCenter(_:willPresent:completionHandler:) para que se userNotificationCenter(_:willPresent:completionHandler:) llamada.

Resultó que había dos problemas. El primero todavía me confunde un poco: mi versión de implementación de destino se estableció en 11.0, pero mi proyecto se estableció en 10.0. Cambiar el proyecto a 11.0 fue el primer paso. No entiendo completamente esto, pero tal vez haya alguna diferencia en el manejo de notificaciones entre 10.0 y 11.0.

La segunda parte fue el delegado del centro de notificaciones. Noté la nota de Apple en los documentos :

Importante

Debe asignar su objeto delegado al objeto UNUserNotificationCenter antes de que la aplicación termine de iniciarse. Por ejemplo, en una aplicación iOS, debe asignarla en el método de la aplicación ( : willFinishLaunchingWithOptions :) o application ( : didFinishLaunchingWithOptions :) de su aplicación delegada. Asignar un delegado después de llamar a estos métodos puede hacer que pierda las notificaciones entrantes.

Había estado configurando una clase separada de "administrador de notificaciones", que es donde también se ubicaban las devoluciones de llamada (como implementaciones de protocolo de delegado). Tuve una instancia de esto como una var de instancia en mi delegado de aplicación, asumiendo que esto se crearía pronto y no causaría un problema.

Solté un tiempo con la instanciación, etc., pero solo cuando configuré el delegado en mi método de application(_:didFinishLaunchingWithOptions:) e implementé las devoluciones de llamada de delegado en el delegado de la aplicación, pude arreglarlo.

Así que mi código se convirtió, básicamente, en:

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


Tal vez no establezca los identificadores de intenciones de UNNotificationCategory, si el código es el siguiente:

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

no llamará a los métodos de delegado de UNUserNotificationCenter, por lo que debe establecer los identificadores de intención de esta manera:

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