Фоновые уведомления FCM не работают в iOS

У меня проблема с уведомлением FCM на iOS.

Я получаю уведомления с успехом, когда мое приложение находится на переднем плане (обратный вызовdidReceiveRemoteNotification вappdelegate срабатывает), но я не получаю уведомления, когда приложение находится в фоновом режиме (я ничего не вижу в трее уведомлений iOS).

Итак, я думаю, что проблема в формате сообщения, отправленного FCM. JSON, отправленный моим сервером в FCM, имеет следующий формат:

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

Как видите, в моем json есть два блока: один блок уведомлений (для получения уведомлений в фоновом режиме) и один блок данных (для получения уведомлений на переднем плане).

Я не могу понять, почему уведомления в фоновом режиме не получены. Мои сомнения касаются порядка блоков (это проблема, если я поставлю блок «данных» перед блоком «уведомления»?).

РЕДАКТИРОВАТЬ: Больше информации о проблеме.

Это мой 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:.
    }


}

Единственный способ получать сообщения на переднем плане - отключить метод swizzling, установив для FirebaseAppDelegateProxyEnabled значение NO в моем файле info.plist.

В этом случае в документации FCM говорится, что мне нужно реализовать в моем appdelegate.swift два метода:

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

Но если я реализую эти функции, сообщения перестают поступать, даже когда приложение находится на переднем плане.

Я знаю, это очень странно.

РЕДАКТИРОВАТЬ 2:

Когда приложение находится в фоновом режиме, уведомление не получено, но когда я открываю свое приложение, то же самое уведомление получено немедленно (метод didReceiveRemoteNotification срабатывает).

Ответы на вопрос(7)

Ваш ответ на вопрос