2
votes

I am using Firebase FCM to send push notifications from an iOS device. The push notifications did work, until yesterday.

When I now send a push notification, everything shows successful, but nothing is received on the device.

If I send directly via a curl request, this is the response:

{"multicast_id":7815294000653973158,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1510474219556035%ca9ff0f8ca9ff0f8"}]}

If I send from the Notification dashboard on the firebase console, it shows successfully completed.

I have done the following with no success:

  1. Locked in pod for 'FirebaseInstanceID', "2.0.0", as per FCM Push notifications do not work on iOS 11
  2. Generated a new APN key on developer console and replaced the existing key on FCM setup in Firebase
  3. Downloaded a fresh GoogleService-Info.plist and replaced existing
  4. Checked that bundle id's etc all match
  5. Updated firebase pods to latest:

Using Firebase (4.5.0) Using FirebaseAnalytics (4.0.4) Using FirebaseAuth (4.3.1) Using FirebaseCore (4.0.10) Using FirebaseFirestore (0.9.1) Using FirebaseInstanceID (2.0.5) Using FirebaseMessaging (2.0.6)

  1. Turned message swizzling on and off
  2. Setting Messaging.messaging().shouldEstablishDirectChannel = true as per Firebase notifications not working in iOS 11
  3. Deleted this iOS app from firebase console and redone notification setup from the start
  4. Made sure remote notification in Capabilities are still turned on
  5. Restarted my devices

My setup: I call FirebaseApp.configure() in the AppDelegate file in the override init() method:

  override init() {
    super.init()
    FirebaseApp.configure()
  }

In the AppDelegate didFinishLaunchingWithOptions:

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

    // get push notification token id for user
    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()

    return true
}

And then I save my token in userdefaults and persist to database later:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let refreshedToken = InstanceID.instanceID().token() {
        defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)
        print("Token generated: ", refreshedToken)
    } else {
        print("Could not save token becuase error with instance id token")
    }
}

The token generated here I also test with curl as mentioned above and all shows successful.

My GoogleService-Info.plist: enter image description here

My Info.plist: enter image description here

Please let me know if any other info is required.

My Android application is still working as before. I am struggling to understand what could change for the iOS app in one day to cause this, or what I perhaps broke in one day:)

Any help would be greatly appreciated.

1

1 Answers

5
votes

Ok, fixed it. I disable firebase's message swizzling by adding this to my Info.plist: FirebaseAppDelegateProxyEnabled: NO

Further I removed all firebase messaging delegate methods. And generated my own APN token in didRegisterForRemoteNotificationsWithDeviceToken and setting Messaging.messaging().apnsToken = deviceToken in the didRegisterForRemoteNotificationsWithDeviceToken method once token generated.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let refreshedToken = InstanceID.instanceID().token() {
        defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)

        Messaging.messaging().apnsToken = deviceToken

        print("Token generated: ", refreshedToken)
    } else {
        print("Could not save token becuase error with instance id token")
    }
}

Previously I used the firebase swizzling, it appears as if this stopped working for some reason.

As this was a tough experience for me, I would like to post the steps that I would now reccommend to enable iOS client for FCM:

  1. In the Apple Developer console generate your APN and then select APNs. Select Continue and download your APN certificate. Take note of your Key ID.

enter image description here

Then in the firebase console under settings, cloud messaging, upload your APN key, add the key ID and bundle id, do not upload any p12 certificates.

enter image description here

  1. Disable firebase message swizzling by adding this to your Info.plist:

FirebaseAppDelegateProxyEnabled: NO

  1. Then add the following in your AppDelegate.swift file in the didFinishLaunchingWithOptions method:

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

    // [START set_messaging_delegate]
    Messaging.messaging().delegate = self
    // [END set_messaging_delegate]
    
    // get push notification token id for user
    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()
    
    return true
    

    }

Since swizzling is disabled you need to take care of generating your APN token and assigning it to the firebase messaging apnsToken. You do this by having the following method in your AppDelegate.swift file:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let refreshedToken = InstanceID.instanceID().token() {
        defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)

        Messaging.messaging().apnsToken = deviceToken

        print("Token generated: ", refreshedToken)
    } else {
        print("Could not save token becuase error with instance id token")
    }
}

I then save the token in the userdefaults to later persist to the database see above:

defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)

You can test that your token is working by copying the token printed out in the console and using the FCM messaging console. Or by using a curl request in the terminal as below. Note you have to replace YOUR_LEGACY_SERVER_KEY with the legacy server key which you can find in the firebase console under settings and cloud messaging and replace YOUR_TOKEN with the token printed in the console (which was generated above):

curl -X "POST" "https://fcm.googleapis.com/fcm/send" \
 -H "Authorization: key=YOUR_LEGACY_SERVER_KEY” \
 -H "Content-Type: application/json" \
 -d $'{
"notification": {
"body": "Testing with direct FCM API",
"title": "Test Message",
"badge": "0",
"sound": "default"
},
"registration_ids": [YOUR_TOKEN]
}'