iosfirebasefirebase-cloud-messaging

FCM error 400 - The registration token is not a valid FCM registration token


We have an ionic/capacitor app that has been using Firebase FCM for push notifications with everything working fine. We just updated to Capacitor 6 and rebuilt the app, reinstalling the @capacitor/push-notifications plug and configuring the various project files.

Everything is working great on Android. But on iOS we get the following error when attempting to send push notifications:

HTTP/1.1 400 Bad Request
Vary: Origin
Vary: X-Origin
Vary: Referer
Content-Type: application/json; charset=UTF-8

{
"error": {
"code": 400,
"message": "The registration token is not a valid FCM registration token",
"status": "INVALID_ARGUMENT",
"details": [
  {
    "@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError",
    "errorCode": "INVALID_ARGUMENT"
  }
]
}
}

Nothing is different on the server side in terms of how we are sending the notification, so it's clearly something wrong with our iOS configuration (since it works fine on Android). So with that in mind, here are the file configurations we've done in xCode.

In the Podfile:

target 'App' do
  capacitor_pods
  # add your pods here
  pod 'Firebase/Messaging'
end

In AppDelegate:

// Push notifications
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDeletage {

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

    // Push Notifications
    FirebaseApp.configure()

    return true
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
   NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}

When running the app from xCode on a local device it appears to be working fine and logs the following as the app registers and obtains a token:

[log] FCM - register: granted
[log] FCM - registration: {"value":"7A868F9E49853DA0F175ABDCE683310CC279306B4B00B579DA94690273CE7A3A"}

When checking the server side to ensure that same token is being used (which was obtained just seconds before), it is indeed the same.

What am I missing?


Solution

  • After a lot more trial and error and research I was able to determine that the official @capacitor/push-notifications docs at https://capacitorjs.com/docs/apis/push-notifications for iOS configuration are wrong. Specifically, the additional code for AppDelegate.swift (which worked fine as outlined there for earlier versions of the plugin) does not work because the current functionality actually retrieves and Apple APN token.

    This is the code in the docs that does not work:

    func application(_ application: UIApplication, 
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      NotificationCenter.default.post(name: 
    .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
    }
    
    func application(_ application: UIApplication, 
    didFailToRegisterForRemoteNotificationsWithError error: Error) {
      NotificationCenter.default.post(name: 
    .capacitorDidFailToRegisterForRemoteNotifications, object: error)
    }
    

    Instead use the following:

    func application(_ application: UIApplication, 
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      Messaging.messaging().apnsToken = deviceToken
      Messaging.messaging().token(completion: { (token, error) in
        if let error = error {
            NotificationCenter.default.post(name: 
    .capacitorDidFailToRegisterForRemoteNotifications, object: error)
        } else if let token = token {
            NotificationCenter.default.post(name: 
    .capacitorDidRegisterForRemoteNotifications, object: token)
        }
      })
    }
    
    func application(_ application: UIApplication, 
    didFailToRegisterForRemoteNotificationsWithError error: Error) {
      NotificationCenter.default.post(name: 
    .capacitorDidFailToRegisterForRemoteNotifications, object: error)
    }
    

    That will retrieve the correct token. Hopefully this saves someone else some time!