Firebase Notification To Device with FCM Token Say

2019-02-10 19:13发布

I am attempting to send a simple push notification from the firebase notification console to a specific device using an FCM token. The firebase notification console shows the notification as sent but the device does not receive it. I have tried sending the notification and then waiting to see if the console logs from didReceiveRemoteNotification, but the notification takes too long (hours) to be shown as sent in the firebase console (even when I set the priority to high).

App Delegate

import UIKit
import Firebase
import FirebaseStorage
import FirebaseDatabase
import FirebaseMessaging
import CoreData
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Use Firebase library to configure APIs
        FirebaseApp.configure()

        /////
        // For Firebase Cloud Messaging (FCM)
        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()
        // End of [for Firebase Cloud Messaging (FCM)]
        /////

        return true
    }

    ///////////////////////
    // FCM Setup

    // Monitor token generation for FCM: Be notified whenever the FCM token is updated
    func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
    }

    // Monitor token generation for FCM:
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().apnsToken = deviceToken
    }    // Handle messages received through the FCM APNs interface
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        print("didReceiveRemoteNotification")
        // 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

        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)

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

^My guess is that the issue may have to do with the "gcm_message_id"/"gcmMessageId"/"gcm.message_id" as it is different in each of the three approaches I tried below

        // Print full message.
        print(userInfo)
    }

    // Handle messages received through the FCM APNs interface
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("didReceiveRemoteNotification (withCompletionHandeler)")
        // 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

        // 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)")
        }

^My guess is that the issue may have to do with the "gcm_message_id"/"gcmMessageId"/"gcm.message_id" as it is different in each of the three approaches I tried below

        // Print full message.
        print(userInfo)

        completionHandler(UIBackgroundFetchResult.newData)
    }

    // End of [FCM Setup]
    ///////////////////////
}

View Controller

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Retrieve the current registration token for Firebase Cloud Messaging (FCM)
        let token = Messaging.messaging().fcmToken
        print("FCM token: \(token ?? "")")
      }
}

Entitlements & Enabling Push Notifications

I have added the push entitlements see here and enabled background modes for push notifications see here and added the GoogleService-Info.plist to my project.

Method for sending Notification

I am creating notification from the Firebase Notifications console (as shown below) so there should be no issue with the structure of the notification itself. enter image description here

I have tried the following approaches to remedy the issue, but all have produced the same result:

Does anyone know why the notification is being marked as sent in the firebase notification console but not showing up on the device?

4条回答
可以哭但决不认输i
2楼-- · 2019-02-10 19:47

I see that you have done everything in your project's Capabilities.

Some points:

  • Conform your class to messaging delegate like so:

    Messaging.messaging().delegate = self
    
  • Make sure you've setup your certificates properly and uploaded everything on Firebase Push Notification Configurations (not exact term).

  • I've done several applications that uses Firebase Push Notification Service and making a sample app from scratch might help you figure out what you've been doing wrong.

And... here's a nicer code block for registering your application for push notification.

    // Setup Push Notifications

    if #available(iOS 10.0, *) {
        let center  = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
            if error == nil{
                DispatchQueue.main.async(execute: {
                    application.registerForRemoteNotifications()
                })
            }
        }
    }
    else {
        let notificationTypes: UIUserNotificationType = [.sound, .alert, .badge]
        let notificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
        application.registerForRemoteNotifications()
        application.registerUserNotificationSettings(notificationSettings)
    }
查看更多
Animai°情兽
3楼-- · 2019-02-10 19:56

A couple of troubleshooting steps I use when working with push notifications are:

  1. Get push working independent of the firebase services first. I use this tool.
  2. Make sure that you dont have any bundle identifier namespace collisions. So for example having any combination of appstore build, testflight build, and / or develop build of an app on the device. Delete all but one instance of the app. The bundle identifier is how your device knows which app to route the push notification to.
  3. When all else fails - I try to isolate the issue by building a new sample project and hook it up to a new firebase project and see if I can narrow my focus down to just being able to get push working without any other business logic in my app. This helps me prove to my self that I haven't gone insane, and proves to me that it's not some mysterious network condition leading to my woes.

I hope this helps you as you work get it all figured out.

查看更多
小情绪 Triste *
4楼-- · 2019-02-10 19:58

Try to add the following code to didRegisterForRemoteNotificationsWithDeviceToken func:

Messaging.messaging().apnsToken = deviceToken

So it will look like this:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    Messaging.messaging().apnsToken = deviceToken
}

It is work for me.

查看更多
我只想做你的唯一
5楼-- · 2019-02-10 20:07

Does anyone know why the notification is being marked as sent in the firebase notification console but not showing up on the device?

Because "sent" does not mean "received".

Notifications cannot be guaranteed to be received on the device. With basic APNS infrastructure you even cannot get the information if a notifications was received or processed on the device.

If you don't receive a successfully sent message on the device there can be many reasons. Furthermore, even if you receive a Firebase token, that does not mean that your device can receive the notification in any case.

To isolate the problem I would suggest to build up the minimal setup and use APNS without Firebase. You could use Terminal or NWPusher (https://github.com/noodlewerk/NWPusher) for sending notifications from your local macOS system and the iOS native remote push notifications framework for receiving notifications.

Keep care to convert the APNS device token to the correct format required for submitting a notification:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    let token = deviceToken.hexEncodedString()
    print("Token: \(token)")
}

Data extension:

extension Data {
    func hexEncodedString() -> String {
        return map { String(format: "%02hhx", $0) }.joined()
    }
}
查看更多
登录 后发表回答