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).
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.
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
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)
content_available = true au niveau supérieur (pas de message de charge utile)
content_available = true dans les notifications (avec le message {titre/corps})
content_available = true au niveau supérieur (avec un message de charge utile)
CONCLUSIONS:
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.
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
-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.