Функция didReceiveRemoteNotification не вызывается с сервером уведомлений FCM

Я использую сервер FCM для удаленных уведомлений, он отлично работал с отправкой и получением уведомлений.

Моя проблема в том, что когда устройство находится в фоновом режиме, эта функция func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) не вызывается.

Решения, которые я пробовал:

  • Эта функция:

    userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
    

вызывается, когда пользователь нажимает на уведомление. В противном случае он не срабатывает.

  • Добавление "content-available": true, "priority": "high" к полезной нагрузке. Кроме того, я пробовал это значение "content-available": 1.

  • Это мой код функции:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
        print("userInfo: \(userInfo)")
      completionHandler(.newData);
  
    }


person Noura Aziz    schedule 14.10.2018    source источник
comment
Если вы тестируете с помощью Postman, попробуйте изменить "content-available": true на "content_available" : true. content-available отправит уведомление, но не вызовет didReceiveRemoteNotification.   -  person iUser    schedule 17.10.2018
comment
Да!! это решено с помощью этого решения! Спасибо, вы мне очень помогли!   -  person Noura Aziz    schedule 24.10.2018
comment
Рад, что это помогло. Не возражаете ли вы принять это как ответ, чтобы он тоже мог помочь кому-то еще.   -  person iUser    schedule 24.10.2018
comment
Конечно! Вы заслуживаете, что.   -  person Noura Aziz    schedule 25.10.2018


Ответы (6)


Если вы тестируете с помощью Postman, попробуйте изменить "content-available": true на "content_available" : true. content-available отправит уведомление, но не вызовет didReceiveRemoteNotification.

person iUser    schedule 24.10.2018

Все, что вам нужно, чтобы увидеть удаленное уведомление в фоновом и переднем плане и показать его как предупреждение при запуске приложения, — это этот appDelegate.swift, который я использовал в своем коде:

import Firebase
import UserNotifications
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate  {
    var window: UIWindow?
    let gcmMessageIDKey = "gcm_message_id"
    var deviceID : String!


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {



        // [START set_messaging_delegate]
        Messaging.messaging().delegate = self
        // [END set_messaging_delegate]

        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()
        FirebaseApp.configure()
        Fabric.sharedSDK().debug = true
        return true

    }

    func showNotificationAlert(Title : String , Message : String, ButtonTitle : String ,window : UIWindow){
        let alert = UIAlertController(title: Title, message: Message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: ButtonTitle, style: .cancel, handler: nil))
        window.rootViewController?.present(alert, animated: true, completion: nil)

    }

    // [START receive_message] remote notification
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {

        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.

        print(userInfo)

    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)
        completionHandler(UIBackgroundFetchResult.newData)

    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }

    // This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
    // If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
    // the FCM registration token.
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("APNs token retrieved: \(deviceToken)")

        // With swizzling disabled you must set the APNs token here.
        // Messaging.messaging().apnsToken = deviceToken
    }
}

// [START ios_10_message_handling]
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

    // Receive displayed notifications for iOS 10 devices.
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)



        // Change this to your preferred presentation option
        completionHandler([.alert, .badge, .sound])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }


        if let aps = userInfo["aps"] as? NSDictionary {
            if let alert = aps["alert"] as? NSDictionary {
                if let title = alert["title"] as? NSString {
                    let body = alert["body"] as? NSString
                    showNotificationAlert(Title: title as String, Message: body! as String, ButtonTitle: "Ok", window: window!)
                }
            } else if let alert = aps["alert"] as? NSString {
                print("mohsen 6 =\(alert)")
            }
        }
        // Print full message.
        print(userInfo)


        completionHandler()
    }
}
// [END ios_10_message_handling]

extension AppDelegate : MessagingDelegate {
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
        deviceID = fcmToken

        let dataDict:[String: String] = ["token": fcmToken]
        NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }
    // [END refresh_token]
    // [START ios_10_data_message]
    // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
    // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }
    // [END ios_10_data_message]


}
person Mohsen Sedaghat Fard    schedule 15.10.2018

Просто добавление принятого ответа: в моем случае проблема была такой же, но поскольку я отправляю уведомление через http "POST" NSMUtableRequest, способ применить принятый ответ состоял в том, чтобы фактически добавить его в параметры уведомления вместе со звуком, значком, плитками и т. д. так далее..

let postParams: [String : Any] = [
                "to": receiverToken,
                "notification": [
                    "badge" : 1,
                    "body": body,
                    "title": title,
                    "subtitle": subtitle,
                    "sound" : true, // or specify audio name to play
                    "content_available": true, // this will call didReceiveRemoteNotification in receiving app, else won't work
                    "priority": "high"
                ],
                "data" : [
                    "data": "ciao",
            ]
                ]

Надеюсь, это также поможет другим, так как я потратил много времени, пытаясь понять, как применить это решение. Большое спасибо.

person Vincenzo    schedule 30.05.2019

Первое, что вам нужно проверить, это то, что Background Mode > Remote Notification включен. В противном случае он не будет вызываться в фоновом режиме.

person Ryan    schedule 14.10.2018
comment
Да, это проверено в возможностях проекта. - person Noura Aziz; 14.10.2018

Шаг 1. Добавьте структуру

import UserNotifications

Шаг 2. Наследование AppDelegate с помощью UNUserNotificationCenterDelegate

final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {}

Шаг 3. Внесите соответствующие изменения в registerPushNotifications и назовите его didFinishLaunchingWithOptions.

private func registerPushNotifications() {
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.currentNotificationCenter().delegate = self
        UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions([.Badge, .Sound, .Alert], completionHandler: { granted, error in

            if granted {
                UIApplication.sharedApplication().registerForRemoteNotifications()
            } else {
                    // Unsuccessful...
            }
          })
    } else {
        let userNotificationTypes: UIUserNotificationType = [.Alert, .Badge, .Sound]
        let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        UIApplication.sharedApplication().registerForRemoteNotifications()
   }
}

Шаг 4. Внедрение новых обработчиков

    // leave this for older versions 
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
}

// For iOS10 use these methods and  pay attention how we can get userInfo
// Foreground push notifications handler
@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
    if let userInfo = notification.request.content.userInfo as? [String : AnyObject] {
        // Getting user info
    }
    completionHandler(.Badge)
 }

// Background and closed  push notifications handler
@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void)  {
    if let userInfo = response.notification.request.content.userInfo as? [String : AnyObject] {
        // Getting user info
    }
    completionHandler()
}
person excitedmicrobe    schedule 14.10.2018
comment
Независимо от того, я не хочу, чтобы вы теряли надежду, у Firebase есть множество проблем в v5, это так, и это был мой метод в Firebase 3, когда они все испортили; Пришлось перейти на OneSignal. Они также поддерживают CURL. - person excitedmicrobe; 14.10.2018
comment
Да, я так думаю. Потому что у меня есть другие проблемы из-за версий Firebase. - person Noura Aziz; 14.10.2018
comment
Если вы когда-нибудь передумаете, это не большой выбор; Я буду здесь для любых проблем с OneSignal. - person excitedmicrobe; 14.10.2018

Как вы ни пытались, я верю во все, фоновое разрешение включено, доступный контент является частью полезной нагрузки, вы также получаете уведомление в активном состоянии, последним будет Power save mode, вам нужно проверить, отключено ли энергосбережение; как будто ваш телефон находится в режиме энергосбережения, тогда фоновое обновление и другие процессы переходят в ограниченное состояние, поэтому приложение не будет вызывать didReceivedNotifcation в фоновом режиме.

person M Abubaker Majeed    schedule 14.10.2018
comment
Я только что попробовал ваше решение, но, к сожалению, оно не вызывается в фоновом режиме. - person Noura Aziz; 15.10.2018
comment
"content-available": 1 должен быть частью апс в полезной нагрузке; Ознакомьтесь с документацией Apple (developer.apple.com/library/archive/documentation/ ). - person M Abubaker Majeed; 15.10.2018