0

Firebase's didReceiveRegistrationToken as seen below is getting called even if the user hasn't granted push notification permissions. I need to make sure that APNS push tokens are being registered for analytics, as well as for saving it on my server, but this function is getting called even when the user hasn't granted push permission. ‍♂️

/**
 * Requirement for Firebase push notifications.
 * See documentation here: https://firebase.google.com/docs/cloud-messaging/ios/client
 */
extension AppDelegate: MessagingDelegate {
    // Note: This callback is fired at each app startup and whenever a new token is generated.
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
        let dataDict: [String: String] = ["token": fcmToken]
        NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
        print("Getting called even if the user hasn't opted in for push notifications!")
    }
}
Zorayr
  • 23,770
  • 8
  • 136
  • 129

2 Answers2

1

TL;DR: FCM token is not a reliable way to detect if APNS token is registered. Disable method swizzling in firebase and listen to APNS registration manually.

  1. FCM Tokens: An FCM token is also known as a device instance ID; it identifies that specific app on that specific device. In other words, FCM token doesn't equal an APNS token. Here is one explanation: APNs, FCM or GCM token.

  2. FCM Token Auto Generation: Surprisingly, even without iOS user granting permission, Firebase generates an FCM token on app launch. I guess it wants to find a way to identify the app & device pair, so as soon as you launch, you're gonna have an FCM token. If you want, you can disable auto-generation and wait for the user to opt-in.

By default, the FCM SDK generates a registration token for the client app instance on app launch. If you want to get an explicit opt-in before using Instance ID, you can prevent generation at configure time by disabling FCM. To do this, add a metadata value to your Info.plist (not your GoogleService-Info.plist):

Here lies one of the problems! Even if the user has disabled auto-generated of FCM tokens, one will be generated when the user is prompted to enable push notifications not when the user has accepted push notification permission. This seems quiet odd and I ended up reporting this to Firebase.

  1. APNS Token Swizzling: So by default Firebase takes over AppDelegate's didRegisterForRemoteNotificationsWithDeviceToken (called "swizzling"). You can disable this and override the delegate method yourself. This will then give you access to both APNS token as well as FCM token.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    print("Successfully registered for notifications!")
    // Required to make FCM work since we disabled swizzling!
    Messaging.messaging().apnsToken = deviceToken
    // String version of APNS so we can use save it/use it later/do analytics.
    let apnsToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
}
Zorayr
  • 23,770
  • 8
  • 136
  • 129
0

Getting a callback for a device ID token and getting a callback for an actual pushed message are two different things. The device ID token callback just gives you a token that identifies the device for a later push notification. It isn't actually a pushed notification itself. It's just an ID.

That said, if you disagree with the behavior of the client SDK from a security perspective, you're free to contact Firebase support directly with feedback.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Maybe my question wasn't clear, I am not looking for device ID, I am looking to know when the APNS push token has been registered. – Zorayr Jul 23 '20 at 01:04
  • Could you edit the question to say why it matters? Is something not working the way you expect when it comes time to actually send a message? Are you encountering a potential security hole? – Doug Stevenson Jul 23 '20 at 01:22
  • Updated, let me know if this is more clear; security is not a concern at this point. – Zorayr Jul 23 '20 at 01:41
  • Well, I already gave an explanation why it's getting called at all. If that's not a problem to you, then I'd leave that out of the question description. Now you're also saying it's getting called too often? How often do you think it should be getting called? I'm having problems getting to what your real question is here. – Doug Stevenson Jul 23 '20 at 01:48
  • Maybe we are using two different terminologies here. Your equivalent of "device ID token" is my "APNS push token"; this is actually what I care about, but `didReceiveRegistrationToken` is giving me this ID even if the user hasn't accepted the push notification permission on iOS? To make sure we are on the same page, I do not care about pushed messages or actual notifications. – Zorayr Jul 23 '20 at 01:52
  • I meant, in the context of this question, I don't care about a specific notification, I just need to know when my app has received the actual APNS push token so I can log it into my analytics and sleep well knowing that the request push notifications permission → user accepting → app getting push token funnel is working fine. – Zorayr Jul 23 '20 at 02:08
  • Are you sure you don't just want to use Apple's own APIs? https://stackoverflow.com/questions/39565172/get-the-push-notification-token-ios-10-swift-3 – Doug Stevenson Jul 23 '20 at 02:15
  • I am using Firebase Cloud Messaging so I don't have to write my own APNS push service; my questions stems from the fact that FCM's push token announcement happens even if the user hasn't granted the push permission, this seems to be a bug! – Zorayr Jul 23 '20 at 02:28
  • OK, well as I said in my answer, contact Firebase support if you disagree with the behavior. – Doug Stevenson Jul 23 '20 at 02:58
  • If I turn off swizzling, I should be able to get APNS push, the question is if there is a better way of doing this: https://medium.com/fantageek/push-notification-in-ios-with-firebase-1c25f39ca578 – Zorayr Jul 25 '20 at 22:37
  • See my answer below ;) – Zorayr Jul 27 '20 at 19:30