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é).