web-dev-qa-db-fra.com

didReceiveRemoteNotification ne fonctionne pas en arrière-plan

Je travaille sur une grande application avec un énorme morceau de code hérité. Actuellement - il existe une implémentation pour:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

Le problème est qu'il n'est appelé que lorsque l'application est au premier plan OR lorsque l'utilisateur appuie sur la notification alors que l'application est en arrière-plan. J'ai essayé de mettre en œuvre:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

Mais l'application se comporte de la même manière. Dans tous les cas, cette méthode n'est pas appelée lorsque l'application est en arrière-plan. Quel pourrait être le problème?

35
YogevSitton

Implémentation de didReceiveRemoteNotification et didReceiveRemoteNotification:fetchCompletionHandler est la bonne façon, mais vous devez également procéder comme suit:

Assurez-vous de vous inscrire pour les notifications à distance, voir documentation ici :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];

    return YES;
}

Assurez-vous également de modifier Info.plist et cochez les cases "Activer les modes d'arrière-plan" et "Notifications à distance":

enter image description here

De plus, vous devez ajouter "content-available":1 à votre charge utile de notification Push, sinon l'application ne sera pas réveillée si elle est en arrière-plan (voir documentation ici ):

Pour qu'une notification Push déclenche une opération de téléchargement, la charge utile de la notification doit inclure la clé de contenu disponible avec sa valeur définie sur 1. Lorsque cette clé est présente, le système réveille l'application en arrière-plan (ou la lance en arrière-plan) et appelle l'application du délégué d'application: didReceiveRemoteNotification: fetchCompletionHandler: method. Votre implémentation de cette méthode doit télécharger le contenu pertinent et l'intégrer dans votre application

La charge utile devrait donc au moins ressembler à ceci:

{
    aps = {
        "content-available" : 1,
        sound : ""
    };
}
69
Baris Akar
  1. Inscrivez-vous à la notification Push dans le délégué de l'application.
  2. Ajoutez le mode d'arrière-plan dans les capacités de l'application.
  3. Ajoutez "content-available" = "1" lors de l'envoi de la notification Push (si vous utilisez Firebase, remplacez "content-available" = "1" par "content_available" = "true" lors de l'envoi de la notification Push côté serveur).
13
Mahadev Mandale

J'ai eu le même problème. Une bannière de notification est apparue, mais -application: didReceiveRemoteNotification: fetchCompletionHandler: la méthode n'a pas été appelée. La solution pour moi qui a fonctionné était d'ajouter l'implémentation de - application: didReceiveRemoteNotification: méthode et transférer l'appel à -application: didReceiveRemoteNotification: fetchCompletionHandler ::

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {

    self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in

    }
}
5
ZaEeM ZaFaR

Je crée un projet iOS qui utilisera Firebase Cloud Messaging (FCM) pour fournir des éléments de données personnalisés, envoyés via des notifications Firebase/APNS, d'un serveur d'entreprise vers l'appareil iOS.

La première chose que j'ai dû comprendre est que, contrairement à Android, il n'y a pas de type de `` service '' similaire qui pourra capturer et enregistrer les informations que j'envoie, que l'application soit au premier plan (active), en arrière-plan (toujours en mémoire) ou non actif (pas en mémoire). Par conséquent, je dois utiliser des messages de notification PAS des messages de données comme je l'avais conçu pour Android.

Après beaucoup de lecture pour comprendre les deux Apple APNS et l'interface Firebase entre l'application iOS et le serveur APNS, en regardant d'innombrables publications sur stackoverflow et d'autres ressources Web, j'ai finalement compris comment faire fonctionner cela pour mes besoins.

Lorsqu'un message de notification Firebase Cloud Messaging (FCM) est envoyé à partir du serveur (ou de la console Firebase car le FCM utilise par défaut les messages Notification NOT Data), il est délivré via APNS et présenté comme une notification sur l'appareil iOS. Lorsque l'utilisateur appuie sur la bannière de notification, iOS fait ce qui suit: si l'application n'est pas en cours d'exécution/chargée iOS lance l'application, si l'application est chargée/en cours d'exécution mais en arrière-plan iOS met l'application au premier plan OR si l'application est au premier plan (dans les trois cas), le contenu du message est ensuite remis via l'application func (_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler complétHandler: (UIBackgroundFetchResult) ->> Vide) {}.

Une chose est sûre, vous devez activer les modes d'arrière-plan et vérifier la notification à distance, vous n'avez PAS à inclure {"content-available": 1} dans la charge utile.

1) Parcourez la configuration APNS et Firebase, assez simple, générez et enregistrez des certificats et autres.

2) Dans appDelegate, didFinishLaunchingWithOptions, ajoutez:

        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) Ajoutez ensuite ces fonctions de rappel à 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])
    }

Très utile:

https://developer.Apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html

0
AndyW58