web-dev-qa-db-fra.com

Les notifications d'arrière-plan FCM ne fonctionnent pas sous iOS

J'ai un problème avec la notification FCM sur iOS.

Je reçois des notifications avec succès lorsque mon application est au premier plan (le rappel didReceiveRemoteNotification dans appdelegate est déclenché), mais je ne reçois pas de notifications lorsque l'application est en arrière-plan (je ne vois rien dans le panneau de notification d'iOS).

Donc, je pense que le problème réside dans le format du message envoyé par FCM . Le json envoyé par mon serveur à FCM est au format suivant:

{  
   "data":{  
      "title":"mytitle",
      "body":"mybody",
      "url":"myurl"
   },
   "notification":{  
      "title":"mytitle",
      "body":"mybody"
   },
   "to":"/topics/topic"
}

Comme vous pouvez le constater, mon json comporte deux blocs: un bloc de notification (pour recevoir des notifications en arrière-plan) et un bloc de données (pour recevoir des notifications en avant-plan).

Je ne comprends pas pourquoi les notifications en arrière-plan ne sont pas reçues ..__ Mes doutes portent sur l'ordre des blocs (un problème se pose-t-il si je mets le bloc "data" avant le bloc "notification"?).

EDIT: Plus d'informations sur le problème.

Ceci est mon appdelegate.Swift:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
    var window: UIWindow?


    // Application started
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
    {
        let pushNotificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
        application.registerUserNotificationSettings(pushNotificationSettings)
        application.registerForRemoteNotifications()

        FIRApp.configure()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "tokenRefreshNotification:", name: kFIRInstanceIDTokenRefreshNotification, object: nil)

        return true
    }




    // Handle refresh notification token
    func tokenRefreshNotification(notification: NSNotification) {
        let refreshedToken = FIRInstanceID.instanceID().token()
        print("InstanceID token: \(refreshedToken)")

        // Connect to FCM since connection may have failed when attempted before having a token.
        if (refreshedToken != nil)
        {
            connectToFcm()

            FIRMessaging.messaging().subscribeToTopic("/topics/topic")
        }

    }


    // Connect to FCM
    func connectToFcm() {
        FIRMessaging.messaging().connectWithCompletion { (error) in
            if (error != nil) {
                print("Unable to connect with FCM. \(error)")
            } else {
                print("Connected to FCM.")
            }
        }
    }


    // Handle notification when the application is in foreground
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
            // If you are receiving a notification message while your app is in the background,
            // this callback will not be fired till the user taps on the notification launching the application.
            // TODO: Handle data of notification

            // Print message ID.
            print("Message ID: \(userInfo["gcm.message_id"])")

            // Print full message.
            print("%@", userInfo)
    }


    // Application will enter in background
    func applicationWillResignActive(application: UIApplication)
    {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }



    // Application entered in background
    func applicationDidEnterBackground(application: UIApplication)
    {
        FIRMessaging.messaging().disconnect()
        print("Disconnected from FCM.")
    }



    // Application will enter in foreground
    func applicationWillEnterForeground(application: UIApplication)
    {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }



    // Application entered in foreground
    func applicationDidBecomeActive(application: UIApplication)
    {
        connectToFcm()

        application.applicationIconBadgeNumber = 0;
    }



    // Application will terminate
    func applicationWillTerminate(application: UIApplication)
    {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


}

Le seul moyen de recevoir des messages au premier plan consiste à désactiver la méthode swizzling, en définissant FirebaseAppDelegateProxyEnabled sur NO dans mon info.plist.

Dans ce cas, la documentation FCM indique que je dois implémenter dans mon appdelegate.Swift deux méthodes:

 - FIRMessaging.messaging().appDidReceiveMessage(userInfo)  in didReceiveRemoteNotification callback
 - FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox) in didRegisterForRemoteNotificationsWithDeviceToken callback

Mais si j'implémente ces fonctions, les messages arrivent même lorsque l'application est au premier plan.

Je sais que c'est très étrange. 

EDIT 2:  

Lorsque l'application est en arrière-plan, la notification n'est pas reçue, mais lorsque j'ouvre mon application, la même notification est reçue immédiatement (la méthode didReceiveRemoteNotification est déclenchée).

31
Mark O' Brian

En supposant que vous ayez tout configuré correctement, définissez la variable priority du message de normal à high devrait le faire apparaître immédiatement. Cela est dû à la manière dont iOS regroupe les notifications et les gère. Vous pouvez lire sur la priorité Priority des notifications FCM ici . Veuillez noter que vous ne devriez pas vraiment utiliser high en production, à moins que cela ne soit justifié, car cela entraîne une pénalité liée à la batterie.

Voici la référence de la documentation de Apple

La priorité de la notification. Spécifiez l'une des valeurs suivantes:

10 – Envoyer le message Push immédiatement. Notifications avec cette priorité doit déclencher une alerte, un son ou un badge sur le périphérique cible. C'est un erreur d'utiliser cette priorité pour une notification Push contenant uniquement la clé de contenu disponible.

5 — Envoyez le message Push à un moment qui prend en compte la puissance considérations pour l'appareil. Les notifications avec cette priorité pourraient être groupés et livrés en rafales. Ils sont étranglés, et dans certains les cas ne sont pas livrés. Si vous omettez cet en-tête, le serveur APNs définit la priorité à 10.

23
Chris

Vous devez définir la propriété content_available sur true comme suit:

{  
   "data":{  
      "title":"mytitle",
      "body":"mybody",
      "url":"myurl"
   },
   "notification":{  
      "title":"mytitle",
      "body":"mybody",
      "content_available": true
   },
   "to":"/topics/topic"
}

Dans cette section, une zone de note bleue indique: https://firebase.google.com/docs/cloud-messaging/concept-options#notifications

17
Keith Holliday

Priorité et content_available (comme indiqué dans d'autres réponses) sont les éléments clés pour vous assurer de recevoir les notifications. Les tests ont montré des résultats intéressants, alors j'ai pensé les partager ici.

Résultats du test: Swift 3, Xcode 8, iOS 10

Priority = "high" => "immediate" (dans les délais évidents du réseau) la réception du message.

Priorité = "normal" => divers résultats (généralement rapide, bien que plus lent que "élevé")

content_available = true dans les notifications (pas de message de charge utile)

  • Premier plan = données reçues comme prévu
  • Contexte = données reçues comme prévu (lors de l'ouverture de l'application)

content_available = true au niveau supérieur (pas de message de charge utile)

  • Premier plan = données reçues comme prévu
  • Contexte = données reçues comme prévu (lors de l'ouverture de l'application)

content_available = true dans les notifications (avec le message {titre/corps})

  • Premier plan = données reçues DEUX FOIS
  • Contexte = données reçues deux fois (lors de l'ouverture de l'application) 

content_available = true au niveau supérieur (avec un message de charge utile)

  • Premier plan = données reçues DEUX FOIS
  • Contexte = données reçues deux fois (lors de l'ouverture de l'application)

CONCLUSIONS:

  1. Bien que la priorité soit une cause possible de la non-réception des messages, le facteur le plus important est que vous devez avoir un message "content_available" ou un message de charge utile.
  2. content_available DOIT être utilisé sur les données utiles (sans lui, aucun message n'est envoyé).
  3. content_available NE DEVRAIT PAS être utilisé sur des données utiles contenant des messages car cela entraîne l'envoi de doubles messages à partir de FCM.
  4. Aucune différence trouvée dans l'utilisation de content_available dans le niveau supérieur ou dans les notifications.

EDIT: Résultats de tests supplémentaires: - Si vous avez un titre de message, vous DEVEZ avoir un corps de message ou vous ne recevez pas d’alerte. 

La partie étrange de ceci est que vous obtiendrez la vibration, le badge et le son, mais la boîte d'alerte n'apparaîtra que si vous avez un corps ainsi que le titre.

9
CFP Support

Vous devrez peut-être ajouter le droit de notification Push. Pour ce faire, accédez aux paramètres de votre cible, puis cliquez sur "Capacités", puis sur "Notifications push".

 Target Capabilities

9
astromme

lorsque vous utilisez des messages de canal FCM directs, vous ne pouvez pas recevoir de notification en arrière-plan 

ceci est un paragraphe de Document Firebase :

Lorsque le canal direct est activé, le back-end du FCM utilise une file de messages fiable pour suivre les messages en attente lorsque l'application est en arrière-plan ou fermée. Lorsque l'application passe au premier plan et que la connexion est rétablie, le canal envoie automatiquement les messages en attente au client jusqu'à ce qu'il reçoive un accusé de réception.

vous pouvez utiliser l'interface APN du FCM pour recevoir des notifications à la fois au premier plan et à l'arrière-plan

1
hamed moosaei

-Pour FCM lorsque l'application est en arrière-plan ou au premier plan et que la méthode OS <10 Application (_: didReceiveRemoteNotification :) se déclenche.

-Quand l'application est au premier plan et que le système d'exploitation => 10 UserNotificationCenter: willPresentNotification: withCompletionHandler: la méthode sera déclenchée.

-Lorsque l'envoi d'un message de données sans composant de notification: Application (_: didReceiveRemoteNotification :) se déclenchera.

-Lors de l'envoi d'un message de données avec le composant de notification: UserNotificationCenter: willPresentNotification: withCompletionHandler: la méthode sera déclenchée.

0