38 votes

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

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

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

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

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

Comme vous pouvez le voir, il y a deux blocs dans mon json: une notification (bloc de recevoir des notifications en arrière-plan), et un bloc de données (pour recevoir les notifications de foreground).

Je ne comprends pas pourquoi les notifications en arrière-plan ne sont pas reçus. Mes doutes sont sur l'ordre des blocs (est-ce un problème si je mets les "données" bloc avant de la "notification" bloc?).

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

C'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:.
    }


}

La seule façon que je peux recevoir des messages en premier plan, est par la désactivation de la méthode swizzling, réglage FirebaseAppDelegateProxyEnabled PAS dans mes infos.plist.

Dans ce cas, la FCM documentation dit que je dois mettre en œuvre dans ma 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'en œuvre de ces fonctions, les messages s'arrête à l'arrivée, même lorsque l'application est en arrière 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 quand j'ouvre mon application, la même notification est reçue immédiatement (méthode didReceiveRemoteNotification est tiré).

23voto

Chris Points 3374

En supposant que vous avez tout mis en place correctement, alors la configuration de l' priority du message de normal de high devrait faire apparaître immédiatement. Cela est dû à la manière d'iOS bundles notifications et les poignées. Vous pouvez lire au sujet de la Priorité de la FCM notifications ici. Veuillez noter que vous ne devriez pas vraiment utiliser high de la production à moins qu'il y est une bonne affaire pour lui, car il a une batterie de pénalité.

Voici la référence de Apple docs

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

10–pour Envoyer le message push immédiatement. Les Notifications de cette priorité doit déclencher une alerte sonore ou d'un insigne sur le périphérique cible. C'est un erreur d'utiliser cette priorité pour une notification push qui ne contient que le contenu de clé disponible.

5-Envoyez le message push à un moment qui prend en compte la puissance considérations pour l'appareil. Les Notifications avec cette priorité pourrait être regroupés et livré dans les rafales. Elles sont limitées, et dans certains les cas ne sont pas livrés. Si vous omettez cet en-tête, les APNs de serveur de jeux la priorité à 10.

19voto

Keith Holliday Points 1494

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

Il y a une zone de note bleue dans cette section qui indique ceci: https://firebase.google.com/docs/cloud-messaging/concept-options#notifications

10voto

CFP Support Points 1032

Priorité et content_available (comme mentionné 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, j'ai donc pensé à les partager ici.

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

Priorité = "haut" => "immédiate" (à moins évident retards de réseau) de réception de message.

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

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

  • Premier plan = données reçu comme prévu
  • Fond = données reçu comme prévu (lors de l'ouverture de l'app)

content_available = true dans le haut niveau (pas de charge utile du message)

  • Premier plan = données reçu comme prévu
  • Fond = données reçu comme prévu (lors de l'ouverture de l'app)

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

  • Premier plan = données reçu deux fois
  • Fond = données reçu à deux reprises (lors de l'ouverture de l'app)

content_available = true dans le haut niveau (avec une charge utile de message)

  • Premier plan = données reçu deux fois
  • Fond = données reçu à deux reprises (lors de l'ouverture de l'app)

CONCLUSIONS:

  1. Si la Priorité est une cause possible de ne pas recevoir de messages, le facteur le PLUS IMPORTANT est que vous devez avoir soit "content_available" ou d'une charge utile de message.
  2. content_available DOIT être utilisé sur des données uniquement à des charges (sans cela, aucun message n'est jamais envoyé).
  3. content_available ne DOIT PAS être utilisé sur les charges qui contiennent des messages, car il provoque des doubles messages envoyés à partir de la FCM.
  4. Pas de différence dans l'utilisation de content_available dans le haut niveau ou dans les notifications.

EDIT: d'autres résultats de tests: - si vous avez un msg titre, vous DEVEZ avoir un msg corps ou vous ne recevez pas un message d'alerte.

L'étrange partie de ceci est que vous obtenez le vibreur, l'insigne et le son, mais la boîte d'alerte n'apparaîtra pas à moins d'avoir un corps aussi bien que le titre.

9voto

astromme Points 916

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".

Capacités cibles

2voto

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

-Lorsque l'application est au premier plan et de l'OS => 10 userNotificationCenter:willPresentNotification:withCompletionHandler: méthode d'incendie.

-Lors de l'envoi du message de données sans préavis composant: demande(_:didReceiveRemoteNotification:) méthode d'incendie.

-Lors de l'envoi du message de données avec le composant de notification : userNotificationCenter:willPresentNotification:withCompletionHandler: méthode d'incendie.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X