不使用 FCM 通知服务器调用 didReceiveRemoteNotification 函数

Posted

技术标签:

【中文标题】不使用 FCM 通知服务器调用 didReceiveRemoteNotification 函数【英文标题】:didReceiveRemoteNotification function doesn't called with FCM notification server 【发布时间】:2018-10-14 09:04:53 【问题描述】:

我正在使用 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);
  
    

【问题讨论】:

如果您使用 Postman 进行测试,请尝试将 "content-available": true 更改为 "content_available" : truecontent-available 会发送通知,但不会调用didReceiveRemoteNotification 是的!它用这个解决方案解决了!谢谢你,你真的帮了我! 很高兴它有帮助。您是否介意接受它作为答案,以便它也可以帮助其他人。 当然!这是你应得的。 【参考方案1】:

您只需要在后台和前台看到远程通知并在应用运行时显示为警报就是我在代码中使用的这个 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]



【讨论】:

【参考方案2】:

只是添加接受的答案:在我的情况下,问题是相同的,但是当我通过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",
            ]
                ]

希望这也对其他人有所帮助,因为我花了很长时间试图弄清楚如何应用此解决方案。 非常感谢。

【讨论】:

【参考方案3】:

如果您使用 Postman 进行测试,请尝试将 "content-available": true 更改为 "content_available" : truecontent-available 会发送通知,但不会调用didReceiveRemoteNotification

【讨论】:

【参考方案4】:

您需要检查的第一件事是Background Mode > Remote Notification 是否打开。如果没有,则不会在后台模式下调用。

【讨论】:

是的,它已在项目功能中进行了检查。【参考方案5】:

第 1 步 - 添加框架

import UserNotifications

第 2 步 – 用 UNUserNotificationCenterDelegate 继承 AppDelegate

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()

【讨论】:

不相关,我不想让你失去希望,Firebase 在 v5 中有很多问题,这是我在 Firebase 3 中的方法,当时他们搞砸了;我不得不切换到 OneSignal。它们还支持 CURL。 是的,我想是的。因为我有其他问题,因为 Firebase 版本。 如果你改变了主意,那也不是什么好选择;我会在这里解决 OneSignal 的任何问题。【参考方案6】:

正如你所尝试的,我相信每一件事,后台权限是启用的,内容可用是有效载荷的一部分,你也在活动状态收到通知,最后一件事将是Power save mode,你需要检查是否省电离开;好像你的手机处于省电模式,然后后台刷新和其他进程处于受限状态,所以应用不会在后台调用didReceivedNotifcation

【讨论】:

我刚刚尝试了您的解决方案,但不幸的是它没有在后台调用。 "content-available": 1 应该是有效载荷中aps的一部分;请查看苹果文档 (developer.apple.com/library/archive/documentation/…)。

以上是关于不使用 FCM 通知服务器调用 didReceiveRemoteNotification 函数的主要内容,如果未能解决你的问题,请参考以下文章

解析服务器(自托管)不使用 FCM 发送 android 通知

确定是不是从 FCM 通知调用活动

FCM 链接在桌面通知中不起作用

Firebase 通知无法使用 FCM 服务正常工作

Cordova Android 应用程序不接收来自服务器端的 FCM 通知

向 FCM 服务器发送推送通知不起作用