ios - tutorial - didReceiveRemoteNotification no funciona en segundo plano
push notifications ios swift tutorial (4)
- Regístrese para recibir notificaciones push en el delegado de la aplicación.
- Agregue el modo de fondo en las capacidades de la aplicación.
- Agregue "content-available" = "1" mientras envía la notificación push (si está utilizando firebase reemplace "content-available" = "1" por "content_available" = "true" mientras envía la notificación push desde el lado del servidor).
Estoy trabajando en una gran aplicación con una gran cantidad de código heredado. Actualmente, hay una implementación para:
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
El problema es que solo se llama cuando la aplicación está en primer plano O cuando el usuario toca la notificación mientras la aplicación está en segundo plano. Traté de implementar:
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
Pero la aplicación se comporta igual. En cualquier caso, este método no se llama cuando la aplicación está en segundo plano. ¿Cual podría ser el problema?
Estoy creando un proyecto de iOS que utilizará Firebase Cloud Messaging (FCM) para entregar elementos de datos personalizados, enviados a través de notificaciones Firebase / APNS, desde un servidor de la empresa al dispositivo iOS.
Lo primero que tuve que entender es que, a diferencia de Android, no existe un tipo similar de ''Servicio'' que pueda capturar y guardar la información que envío, independientemente de si la aplicación está en primer plano (activa), en segundo plano (aún en memoria) o no activo (no en memoria). Por lo tanto, tengo que usar los mensajes de notificación, NO los mensajes de datos como había diseñado para Android.
Después de mucha lectura para comprender tanto Apple APNS como la interfaz Firebase entre la aplicación iOS y el servidor APNS, mirando innumerables publicaciones en y otros recursos web, finalmente descubrí cómo hacer que esto funcione para mis requisitos.
Cuando se envía un mensaje de notificación de Firebase Cloud Messaging (FCM) desde el servidor (o Firebase Console, ya que el FCM se establece de manera predeterminada en mensajes Notification NOT Data), se entrega a través de APNS y se presenta como una notificación en el dispositivo iOS. Cuando el usuario toca el banner de notificación, iOS hace lo siguiente: si la aplicación no se está ejecutando / cargada, iOS inicia la aplicación, si la aplicación está cargada / ejecutándose pero en segundo plano, iOS pone la aplicación en primer plano O si la aplicación está en primer plano (los tres casos), el contenido del mensaje se entrega a través de la aplicación func (_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completeHandler: (UIBackgroundFetchResult) -> Void) {}.
Una cosa es segura, debe habilitar los modos en segundo plano y verificar la notificación remota, NO tiene que incluir {"contenido disponible": 1} en la carga útil.
1) Ir a través de la configuración APNS y Firebase, bastante sencillo, generar y registrar certificados y demás.
2) En appDelegate, didFinishLaunchingWithOptions, agregue:
Messaging.messaging().delegate = self as? MessagingDelegate
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
}
else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
3) Luego agregue estas funciones de devolución de llamada a appDelegate:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// Print message ID.
if let messageID = userInfo["gcm.message_id"] {
print("/n*** application - didReceiveRemoteNotification - fetchCompletionHandler - Message ID: /(messageID)")
}
// Print full message.
print("/n*** application - didReceiveRemoteNotification - full message - fetchCompletionHandler, userInfo: /(userInfo)")
myNotificationService?.processMessage(title: userInfo["Title"] as! String
, text: userInfo["Text"] as! String, completion: { (success) in
if success {
completionHandler(.newData)
}
else {
completionHandler(.noData)
}
})
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
Muy útil:
https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html
Implementar
didReceiveRemoteNotification
y
didReceiveRemoteNotification:fetchCompletionHandler
es la forma correcta, pero también debe hacer lo siguiente:
Asegúrese de registrarse para recibir notificaciones remotas, consulte la documentación aquí :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
return YES;
}
También asegúrese de editar
Info.plist
y marque las
Info.plist
verificación "Habilitar modos de fondo" y "Notificaciones remotas":
Además, debe agregar
"content-available":1
a su carga útil de notificaciones push, de lo contrario, la aplicación no se despertará si está en segundo plano (consulte la
documentación aquí
):
Para que una notificación push active una operación de descarga, la carga útil de la notificación debe incluir la clave de contenido disponible con su valor establecido en 1. Cuando esa clave está presente, el sistema activa la aplicación en segundo plano (o la inicia en segundo plano) y llama a la aplicación del delegado de la aplicación: didReceiveRemoteNotification: fetchCompletionHandler: method. Su implementación de ese método debe descargar el contenido relevante e integrarlo en su aplicación
Entonces, la carga útil al menos debería verse así:
{
aps = {
"content-available" : 1,
sound : ""
};
}
Yo tuve el mismo problema. Aparece un banner de notificación, pero -aplicación: didReceiveRemoteNotification: fetchCompletionHandler: no se llamó al método. La solución para mí que funcionó fue agregar la implementación de - application: didReceiveRemoteNotification: method y reenviar la llamada a -application: didReceiveRemoteNotification: fetchCompletionHandler ::
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in
}
}