Quickstart-ios: Push Notifications not working after update to Firebase 4.0

Created on 1 Jun 2017  路  61Comments  路  Source: firebase/quickstart-ios

I updated my pods yesterday to the new Firebase 4.0. I went through the suggested changes and grabbed code from this Github example. I installed the APNS key .p8 file from Apple. Re-Downloaded the google.plist file to my project. turned swizzling off. Replaced this examples code with my own. I will be honest I am at a loss, I take the FCM Token from the console and send a message from the firebase console and I get nothing.

I refresh and it says the message was sent but I check the xCode console and the device and nothing is there. What am I missing? Is there any way to figure out where the message is getting jammed up?

//
//  Created by Erik Grosskurth on 4/24/17.
//

import UIKit
import UserNotifications
import Firebase
import Quickblox
import QuickbloxWebRTC

let kQBApplicationID:UInt = 1234
let kQBAuthKey = "sfgsrvsrvsr"
let kQBAuthSecret = "wsevwrvwervwrv"
let kQBAccountKey = "wrvwrvwrvwrvwrvw"

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    let gcmMessageIDKey = "gcm.message_id"

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

        // [ START Quickblox config ]
        QBSettings.setApplicationID(kQBApplicationID)
        QBSettings.setAuthKey(kQBAuthKey)
        QBSettings.setAuthSecret(kQBAuthSecret)
        QBSettings.setAccountKey(kQBAccountKey)
        QBSettings.setApiEndpoint("https://apicaduceustelemed.quickblox.com", chatEndpoint: "chatcaduceustelemed.quickblox.com", forServiceZone: .production)
        QBSettings.setServiceZone(.production)
        QBSettings.setKeepAliveInterval(30)
        QBSettings.setAutoReconnectEnabled(true)
        QBRTCConfig.setStatsReportTimeInterval(1)
        QBRTCConfig.setDialingTimeInterval(5)
        QBRTCConfig.setAnswerTimeInterval(60)
        // [ END Quickblox config ]

        FirebaseApp.configure()

        // [START set_messaging_delegate]
        Messaging.messaging().delegate = self
        // [END set_messaging_delegate]
        // Register for remote notifications. This shows a permission dialog on first run, to
        // show the dialog at a more appropriate time move this registration accordingly.
        // [START register_for_notifications]
        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 register_for_notifications]
        return true
    }

    // [START receive_message]
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        // 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)")
        }

        // Print full message.
        print(userInfo)
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // 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)")
        }

        // Print full message.
        print(userInfo)

        completionHandler(UIBackgroundFetchResult.newData)
    }
    // [END receive_message]
    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([])
    }

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

        // Print full message.
        print(userInfo)

        completionHandler()
    }
}
// [END ios_10_message_handling]

extension AppDelegate : MessagingDelegate {
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
    }
    // [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]
}

Most helpful comment

The bundle ID had a F** typo... FML... SMGDH... Thank you for your time sir, You are the man! I'm going home to cry now... I hate apple, I'm going back to web apps....

All 61 comments

Hi @djErock,

Thanks for sharing your application delegate, everything looks good here. A couple of things to check though:

APNs Working?

Are you getting an APNs token? Just want to confirm that your app has been configured for APNs.

Correct GoogleService-Info.plist

Can you confirm that the GoogleService-Info.plist file you downloaded is for a matching Firebase app entry, and that BUNDLE_ID in the plist matches your app's plist, and that the .p8 file is added for that Firebase app's settings as well? I just saw this same type of issue with a developer who had downloaded a google plist for a _different_ app in their Firebase project.

Testing in foreground?

By default, iOS shows no push notification if the app is running in the foreground. iOS 10 made it easy to allow a push notification to show even in the foreground, though. You can change the completion handler in userNotificationCenter(_:willPresent:withCompletionHandler:) from:

completionHandler([])

to

completionHandler([.alert, .badge, .sound])

Here are the logs:

2017-06-01 14:29:38.187779-0400 Telemed[2125:1076809] [Firebase/Analytics][I-ACS003016] Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
2017-06-01 14:29:38.188 Telemed[2125] <Warning> [Firebase/Analytics][I-ACS003016] Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
2017-06-01 14:29:38.267071-0400 Telemed[2125:1076815] [Firebase/Analytics][I-ACS005000] The AdSupport Framework is not currently linked. Some features will not function properly. Learn more at http://goo.gl/9vSsPb
2017-06-01 14:29:38.267 Telemed[2125] <Warning> [Firebase/Analytics][I-ACS005000] The AdSupport Framework is not currently linked. Some features will not function properly. Learn more at http://goo.gl/9vSsPb
2017-06-01 14:29:38.271773-0400 Telemed[2125:1076809] [Firebase/Analytics][I-ACS023007] Firebase Analytics v.4000000 started
2017-06-01 14:29:38.272 Telemed[2125] <Notice> [Firebase/Analytics][I-ACS023007] Firebase Analytics v.4000000 started
2017-06-01 14:29:38.274861-0400 Telemed[2125:1076809] [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see http://goo.gl/RfcP7r)
2017-06-01 14:29:38.275 Telemed[2125] <Notice> [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see http://goo.gl/RfcP7r)
**FCM token: euL290pzfCY:APA91bEIYldaSVz7AlgQ-nEnDh1ISC112VERT8ZgA6CTlU5NANFy7oqvz238gQ2iGJQZNwLf4ZCD-DsF2iL0YB8Qp9OEBxFRRhDQ9pbov9hl5FER-Q8Zn4ST_i3TrJSEaqV4S1w00Zed**
2017-06-01 14:29:38.360742-0400 Telemed[2125:1076809] [Firebase/Analytics][I-ACS032003] iAd framework is not linked. Search Ad Attribution Reporter is disabled.
2017-06-01 14:29:38.361 Telemed[2125] <Warning> [Firebase/Analytics][I-ACS032003] iAd framework is not linked. Search Ad Attribution Reporter is disabled.
2017-06-01 14:29:38.363630-0400 Telemed[2125:1076815] [Firebase/Analytics][I-ACS023012] Firebase Analytics enabled
2017-06-01 14:29:38.363 Telemed[2125] <Notice> [Firebase/Analytics][I-ACS023012] Firebase Analytics enabled
Destroyed Session but Saved Login
2017-06-01 14:29:38.388645-0400 Telemed[2125:1076765] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-06-01 14:29:38.389130-0400 Telemed[2125:1076765] [MC] Reading from public effective user settings.
**APNs token retrieved: 32 bytes**

screen shot 2017-06-01 at 2 32 43 pm

After refresh:

screen shot 2017-06-01 at 2 33 50 pm

If it's not Firebase and its not the code that only leaves the testing environment and/or APNS...

@rsattar Here is a link to the whole project: https://github.com/djErock/Telemed/tree/master/Telemed

The message successfully completes in the firebase console but never hits the device/console logs... Is there a way to track the message as it goes through the APNS system? I seems as though its getting hung up there. Do I need to replace any provisioning profiles or create new certs or do anything on the Apple dev side of things other than generate the new .P8 file??

screen shot 2017-06-01 at 3 43 51 pm

@rsattar

APNs Working?
Yes, I am receiving an APNS token in the console. See the logs screenshot above. thanks.

Correct GoogleService-Info.plist?
After I uploaded the APNS Auth Key I downloaded a new version of the google.plist file as well and installed it into the xCode project. I have confirmed that the data in the .plist file matches that of whats in the FB console.

Testing in foreground?
Thanks for this but I am not receiving any push notification at all. Nothing logs in the console letting me know that it had retrieved a message.

Here's something we can try to help debug: You can try sending your self push notifications using the FCM HTTP API, here's an example. Fill in your LEGACY_SERVER_KEY with the value in your Firebase Console > Project Settings > Cloud Messaging > Legacy Server Key. Replace FCM_TOKEN with your FCM token:

curl -X "POST" "https://fcm.googleapis.com/fcm/send" \
     -H "Authorization: key=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": [
    "FCM_TOKEN"
  ]
}'

You can paste the curl command into Terminal to see what error message (if any) you're getting.

Sweet: {"multicast_id":4850999595514789154,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidApnsCredential"}]}Eriks-Mac-mini:pushnotificationtest erikgrosskurth$

So does this mean that the APNS credential in the auth key or is it the APNS credential issued at the run time of the app?

What is the multicast_id?

According to: https://firebase.google.com/docs/cloud-messaging/http-server-ref

  • Invalid APNs credentials 200 + error:
    InvalidApnsCredential A message targeted to an iOS device could not be sent because the required APNs SSL certificate was not uploaded or has expired. Check the validity of your development and production certificates.

This is what it says in that section:

screen shot 2017-06-01 at 4 42 44 pm

InvalidApnsCredential refers to an issue in the APNs Auth Key or certificate. Can we make sure that the plist's PROJECT_ID matches the project id for your Firebase app?

screen shot 2017-06-01 at 4 47 33 pm

Looks good from here. Do you see anything out of the ordinary there?

Im going to revoke the initial one and upload a new one to the project and see if we can hit paydirt. One sec

Ran it again and received the same results. {"multicast_id":6377091940157475771,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidApnsCredential"}]}

Curious... in the chain of events in the appDelegate, I register for remote notifications before didRegisterForRemoteNotificationsWithDeviceToken and before the APNS Token is generated in the console. Would that behavior affect the process at all since you would need the APNS token to register with FCM? Should it be the other way around?

Thinking... so after reading here: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/LaunchingYourApponDevices/LaunchingYourApponDevices.html

This feels like a bug... Not sure on which side though...
It states that "Xcode automatically creates your development certificate and registers a connected device" and in the error documentation FCM states "Check the validity of your development and production certificates." Does this mean that the cert that xCode is generating is the invalid one the FCM docs are referring to? (I am running xCode 8.3.2 with iPhone 7 running 10.3.2 on a Mac Mini running Sierra)

Apologies for the confusion, but yeah in places where it says APNs certificates, it should also apply to APNs Auth Keys (Auth Keys were just rolled out a few weeks ago, and some bits of documentation still refer to only certificates).

In general, with Apple's Auth Keys, you don't need to create push notification certificates (sandbox or production). In your app info screenshot from the developer portal, it shows the notifications as Enabled. Does that means you've created certificates for them? I think it's a holdover from pre-Auth Key-Apple too. Those values can safely remain "Configurable" and APNs Auth Keys will still work.

I took a look at your project (thanks for sharing that), and the App Delegate stuff looks good. Your GoogleService-Info.plist is a dummy file, and the real values are actually put in in your app, right? Also: it looks like you _are_ using swizzling, correct? Your Info.plist has:

    <key>FirebaseAppDelegateProxyEnabled</key>
    <true/>

However your logs seem to indicate that the app delegate proxy is disabled. Is that just in your Git workspace?

I have turned swizzling off, that is a dummy file yes, I can send it to you via private message or something if you would like. That is just the GIT workspace as I have been troubleshooting for two days now to no avail so what you see there is a snapshot of where i was at that moment.

Let me get those certs out of the apple config really quick and retry

screen shot 2017-06-01 at 5 27 33 pm

Still failed: {"multicast_id":7995160101627937517,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidApnsCredential"}]}

I have to cut out now. Can we pick this up your time tomorrow? Skype maybe?

screen shot 2017-06-01 at 5 29 36 pm

One more thing: Can you verify that the GOOGLE_APP_ID in the google plist matches your Firebase app's "App ID" in Firebase Console > Project Settings > Your App > App ID?

It should look something like this: 1:SOME_NUMBERS:ios:HEX_STRING

And just to make sure: the Team ID you entered for the APNs Auth Key is the Team ID for this app's bundle id in the Apple Developer Portal?

screen shot 2017-06-02 at 9 00 53 am

screen shot 2017-06-02 at 9 47 14 am

TRIED GOING BACK IN AND PUTTING NEW .P12 APNS certs in and it failed as well. I then created a new .p8 file as shown above uploaded and still:

{"multicast_id":7926595849536980756,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidApnsCredential"}]}

Hmm, so this is getting a bit weird. Let's try and eliminate some possible issues. First, let's make sure APNs is working using that APNs Auth Key directly. That will make sure that the APNs stuff is fine, and it's an issue on FCM's side.

If you have a way to send yourself push notifications directly using APNs, is that working? I just tried out this script on my Mac, though I had to make sure I installed the homebrew versions of curl and openssl which support HTTP/2. I also had to install curl as: brew install curl --with-nghttp2 to make sure HTTP/2 support was added. With that, I can send messages directly using an APNs Auth Key.

Note: there may be other online tools to help debug this.

I am in the process of doing that now. I have to make a .pem file that works first. I have a sinking feeling this has to do with having certs previous first and now changing over to the auth key. Give me some time as I have gotten homebrew and curl set up to send http/2 set up but it said my pem file i made was: curl: (58) could not load PEM client certificate, OpenSSL error error:02001002:system library:fopen:No such file or directory, (no key found, wrong pass phrase, or wrong file format?)

Do you know a way to test using the auth key with curl and the APNS token?

Yeah, this script supports curl with the APNs Auth Key (no certs/pems). However, you have to install a special curl (--with-nghttp2) and openssl from homebrew first.

I tried that but kept getting:
Warning: curl-7.54.0 already installed, it's just not linked.
Warning: openssl-1.0.2l already installed, it's just not linked.

I WAS TRYING TO GET THIS TO RUN: curl --http2 --cert myapp-push-cert.pem -H "apns-topic: com.caduceususa.telemed" -d '{"aps":{"alert":"Hello from APNs!","sound":"default"}}' https://api.development.push.apple.com/3/device/MYAPNSTOKEN

BUT THATS WHEN I GOT THE CERT ERROR

sorry for yelling LOL

OK so I used that script and got this:

< HTTP/2 400
< apns-id: 3D9092F4-2AAA-6FCF-EB60-A17CA6CDBEBC
<

  • Connection #0 to host api.development.push.apple.com left intact
    {"reason":"BadDeviceToken"}

Is the device token the same as the APNS Token given from xCode? Also Am I using this to get the string here:

var readableAPNSToken: String = ""
for i in 0.. readableAPNSToken += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}
print("Received an APNs device token: (readableAPNSToken)")

Is there a better way to get it the Device Token in a different format?

print("APNS Token: (deviceToken.hexByteString)") Maybe???

Here's a category I wrote on Data to print out the APNs device token.

This about sums it all up here LOL:

'''
Here's a category I wrote on Data to print out the APNs device token.
'''

screen shot 2017-06-02 at 1 44 26 pm

Sorry, here's the fixed link

I receive a HTTP/2 200 response:

< HTTP/2 200 
< apns-id: A15A3519-6276-D187-0DB3-CADA8FE28AF0
< 
* Connection #0 to host api.development.push.apple.com left intact

The two reasons for "BadDeviceToken" are if the token is malformed, _OR_ if the token doesn't match the environment (production or sandbox). Is there something unusual about your app signing? Does it work if you send the request to api.push.apple.com instead of api.development.push.apple.com?

BTW, an easier way to do this would be to save that command as a .sh file (e.g. apns.sh) and then you can execute it using sh apns.sh.

Give me a second to parse, Thanks

OK Good News, Now we get {"reason":"DeviceTokenNotForTopic"}

I also tried swapping out

_api.push.apple.com_ with _api.development.push.apple.com_

the production gave: {"reason":"BadDeviceToken"}

the development gave: {"reason":"DeviceTokenNotForTopic"}

According to this: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html

400
DeviceTokenNotForTopic
The device token does not match the specified topic.

Yeah, DeviceTokenNotForTopic usually means that the APNs device token doesn't match the bundle id. Apple Documentation. Something is strange with your app's bundle id or device token. Can you print out the bundle id while the app is running, to confirm it's the same bundle id as what you're sending to APNs? (usually Bundle.main.bundleIdentifier)

The bundle ID had a F** typo... FML... SMGDH... Thank you for your time sir, You are the man! I'm going home to cry now... I hate apple, I'm going back to web apps....

The bundle ID was fine everywhere except in xCode...

screen shot 2017-06-02 at 2 43 21 pm

cam instead of com

@rsattar Can you add an answer here so I can upvote on SO? https://stackoverflow.com/questions/44294144/push-notifications-not-working-in-firebase-4-0

Most of the time, this problem seems to be caused by improper configuration, such a typo in the bundle name, bad entitlements in App ID, etc. However, I discovered that one solution if all else fails is to use your Team ID instead of the App Prefix in the Firebase Cloud Settings. Not the answer here, but that might help someone else. The docs really need to be updated for this!

@johncovele Team ID is the same as App Prefix. Or am I misunderstanding something?

@phonggenix Usually it is, but it doesn't have to be. When dealing with old legacy projects you might find they are different. Current versions of the developer portal and XCode guide you to make them the same.

@johncovele you are correct, for the old apps they are different, I tried both the Team ID and the App Prefix, but still the same issue! do you know how I can resolve this issue?
I'm trying to send push notification through FireBase using .p8 auth file

I have the same issue, switched to .p8, follow all and double checked everything from this discussion but I was not able to get it working? curl returns InvalidApnsCredential Any idea how to resolve this issue ? Also beside this discussion I found on SO that people are complaining about this issue. Thx.

Hey all, if anyone is having FCM issues, please open a new issue. Don't tack +1 comments with few details on months-old issues that may or may not be related.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mingsai picture mingsai  路  5Comments

myflashlab picture myflashlab  路  7Comments

asciiman picture asciiman  路  7Comments

svachmic picture svachmic  路  5Comments

abdulKarim002 picture abdulKarim002  路  6Comments