Skip to content

Messages not received when registration is done after first app launch #254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
pfrischmuth opened this issue Sep 12, 2017 · 25 comments
Closed
Assignees

Comments

@pfrischmuth
Copy link

Environment

  • Xcode version: 8.3.3 (8E3004b)
  • Firebase SDK version: 4.1.1 (happens starting from 4.0.0)
  • Library version: FirebaseMessaging 2.0.2
  • Firebase Product: messaging

Describe the problem

Steps to reproduce:

When I register for push notifications directly when the app starts for the first time (after install), the registration process works and I can send a notification to my device via the Firebase console.

However when I do not register on first app launch (i.e. launching the app for the first time, stopping it and register on second launch), the registration process seems to succeed (I can access the FCM token), but when I send a message via the Firebase console to that token, I will not receive the message.

When I use (almost) the same code (changes only in the commented out lines, due to changes to the API) with a Firebase version <4.0.0 (e.g. Firebase 3.15.0), both cases work fine.

Relevant Code:

I created a very simple project that reproduces the problem. I comment out the code for the first launch and then do the registration on the second launch, which produces the issue.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    // use the following line for Firebase < 4.0.0
    //FIRApp.configure()

    // START: comment out the following block on first app launch
    UNUserNotificationCenter.current().delegate = self

    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: {_, _ in })

    application.registerForRemoteNotifications()

    let token = Messaging.messaging().fcmToken
    // use the following line for Firebase < 4.0.0
    //let token = FIRInstanceID.instanceID().token()
    print("FCM token: \(token ?? "")")
    // END

    return true
}
@katowulf
Copy link

@pfrischmuth thanks for this. Can you note your iOS version and whether you've disabled method swizzling, since those are related to setup and may be needed for a repro?

@pfrischmuth
Copy link
Author

I tested on iOS 10.3.

In the above example I did not disable method swizzling, but I also tried it with method swizzling disabled and the issue still occurs.

@rsattar
Copy link
Contributor

rsattar commented Sep 12, 2017

Hmm this could be related to a bug I'm fixing in Instance ID that was introduced in the last release, where a race condition is created on first launch. (This is being fixed for the next release)

Hmm, to confirm what you're saying:
First Launch

  • Don't register for push notifications
  • Retrieve FCM token anyway
  • Attempt to send push notification fails (expected behavior)

Second Launch

  • Register for push notifications
  • Retrieve FCM token
  • Attempt to push notifications succeeds (expected behavior)

I think I'm misunderstanding the issue, then. However, I want to clarify:

However when I do not register on first app launch (i.e. launching the app for the first time, stopping it and register on second launch), the registration process seems to succeed (I can access the FCM token), but when I send a message via the Firebase console to that token, I will not receive the message.

FCM / IID creates an FCM token whether or not you register for remote notifications, it's just that there is no APNs device token associated with that FCM token yet. When an APNs token is provided, the FCM token is updated on the backend to be associated with that APNs token, and notifications can now be sent via APNs using that FCM token.

@pfrischmuth
Copy link
Author

I tried with Firebase 3.15.0, 4.0.0 and 4.1.1. With both 4.x releases I can produce the issue, with the 3.x release it works as expected (although the API is slightly different).

I don't even access the FCM token on first launch. I only call FirebaseApp.configure() on first launch, since I need this call for other Firebase features (remote config). So I do nothing cloud messaging related on first launch and of course I can not receive notifications then (as expected).

I do all the registration steps on the second launch (or later) and would expect that I can receive notifications afterwards, but this does not work for me (not with a 4.x SDK, with a 3.x SDK it works fine).

However when I complete the registration process on first launch, I can receive notifications (with all tested versions of the SDK).

I hope this clarifies my issue.

@rsattar
Copy link
Contributor

rsattar commented Sep 18, 2017

Thanks @pfrischmuth for the detailed info. Yes, it sounds like the issue that is being fixed in Instance ID for the next release of Firebase.

As a workaround for now, you should be able to call application.registerForRemoteNotifications() on first launch of your app. This is safe to do, and will not show a permissions dialog to the developer. It will provide an APNs token to you (and FCM) even on first launch. For example:

FirebaseApp.configure()
application.registerForRemoteNotifications()

Later on (in your second launch), you can always request permissions for user notifications as you have done before (i.e. UNUserNotificationCenter.current().requestAuthorization(...)).

Hope that makes sense!

@pfrischmuth
Copy link
Author

OK, thanks for the response.

I will consider the workaround and look forward for a fix in the next release.

@ChrisRicca
Copy link

Hi @pfrischmuth I'm trying to determine if the issue I'm seeing is the same as yours. Would it be possible to clarify: when you say "when I send a message via the Firebase console to that token, I will not receive the message.", did you see an error message in the console? (I am seeing "Unregistered Registration Token").

@pfrischmuth
Copy link
Author

Hi @ChrisRicca No, I do not receive an error message in the Firebase Console. I see the usual "Done" state there, but the message is never received on the device.

@paulb777
Copy link
Member

Fixed in Firebase 4.2.0 FirebaseInstanceID 2.0.3 released today.

@pfrischmuth
Copy link
Author

pfrischmuth commented Sep 21, 2017

Unfortunately this fix does not solve my problem.

I think I can narrow the issue down to an issue in FirebaseInstanceID, since when I try it with FirebaseInstanceID 2.0.0 it works fine. I tried the following versions:

FirebaseInstanceID Version Status
2.0.0 working fine
2.0.1 not working
2.0.2 not working
2.0.3 not working

I have a very simple app that just executes the following code on first launch (fresh install of the app):

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

    return true
}

On second launch of the app I execute the following code:

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

    UNUserNotificationCenter.current().delegate = self

    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: {_, _ in })

    application.registerForRemoteNotifications()

    let token = Messaging.messaging().fcmToken
    print("FCM token: \(token ?? "")")

    return true
}

I think I can narrow it down to that calling application.registerForRemoteNotifications() needs to be done on first launch always. However this is not an option in my real application where I need to use Firebase Messaging.

@ChrisRicca
Copy link

I have reproduced this issue as well in our application using the latest release (Firebase 4.2.0 FirebaseInstanceID 2.0.3). At first, the push notifications silently fail as @pfrischmuth described. (I suspect over time they get cleaned up by the firebase system and start returning the "Unregistered Registration Token" error that I was seeing later.)

We can probably call application.registerForRemoteNotifications() as suggested in didFinishLaunchingWithOptions to try to avoid this situation on installation (I am testing this now), but that won't fix the users who are currently in the "broken" state, who keep getting the same (apparently inactive) token back from Messaging.messaging().fcmToken.

Relying on the initial application.registerForRemoteNotifications() call also makes me nervous for this reason. If for whatever reason the notifications aren't setup correctly on first launch (a crash, for example), the user will be stuck in a broken state with no option but to uninstall and reinstall to fix the notifications.

@rsattar
Copy link
Contributor

rsattar commented Sep 21, 2017

@pfrischmuth and @ChrisRicca Thanks so much for the detailed info, particularly the app delegate differences between starts. I've reproduced the issue, and I'm working on a fix. Re-opening this issue.

In the meantime, the workaround is to call application.registerForRemoteNotifications() in our app start, even first launch.

I think I can narrow it down to that calling application.registerForRemoteNotifications() needs to be done on first launch always. However this is not an option in my real application where I need to use Firebase Messaging.

Curious, why is this not an option? FYI, this does not show a permissions dialog to the user, only the application.registerUserNotificationSettings or NotificationCenter.current.requestAuthorization shows the permissions dialog. You do not have to request user notification settings before calling registerForRemoteNotifications().

Relying on the initial application.registerForRemoteNotifications() call also makes me nervous for this reason. If for whatever reason the notifications aren't setup correctly on first launch (a crash, for example), the user will be stuck in a broken state with no option but to uninstall and reinstall to fix the notifications.

Yeah, I'm really sorry for the bug 😞 . Assuming your app doesn't crash while fetching an FCM token, you should be fine.

@rsattar rsattar reopened this Sep 21, 2017
@pfrischmuth
Copy link
Author

Thank you for the response.

I have two concerns regarding always calling application.registerForRemoteNotifications():

  1. As @ChrisRicca stated, we are already using Firebase Messaging with a 3.x release. What happens with users that are updating our app? Will they be in a bad state, because they already used the app before?

  2. I tried the approach in our app and had a strange behavior: When calling requestAuthorizationat a later point after registerForRemoteNotifications was already called, I do not receive the normal authorization dialog that I would expect, but a dialog that I should change settings for notifications in iOS settings.

@ChrisRicca
Copy link

@rsattar thanks for the response, and for being on the case. No need to apologize, bugs happen 🐞! We're implementing another push notification service using the raw APNS token so we can recover our users who are in a broken state, and then we'll switch back when the fix is up so I'm all set, but let me know if there's anything I can do to help. (Same to you @pfrischmuth)

@plu
Copy link

plu commented Sep 25, 2017

Fixed in Firebase 4.2.0 FirebaseInstanceID 2.0.3 released today.

I can also still reproduce the issue in the given versions. Downgrading FirebaseInstanceID to 2.0.0 fixed it (thanks @pfrischmuth).

@FranticRock
Copy link

FranticRock commented Sep 26, 2017

Same problem for me, and same solution.

  1. Moved application.registerForRemoteNotifications() into didFinishLaunchingWithOptions (upon first time app launch).

  2. Updated my Podfile to use FirebaseInstanceID to 2.0.0 EXACTLY. (2.0.3 is problematic):
    pod 'Firebase/Core', '> 4.2.0'
    pod 'Firebase/Messaging', '
    > 4.2.0'
    pod 'Firebase/RemoteConfig', '~> 4.2.0'
    pod 'FirebaseInstanceID', '2.0.0'

And Yes, i do ask for permissions, later. (not on first app launch). So to our user, the experience is unchanged. Just got to make sure our devs know to do this. We will be following this thread to see when we will be able to roll forward to FirebaseInstanceID latest.

NOTE: Just doing # 1 does NOT solve the described problem.

Tested on iOS Versions: 9, 10, 11.

@plu
Copy link

plu commented Sep 26, 2017

Moved application.registerForRemoteNotifications() into didFinishLaunchingWithOptions (upon first time app launch).

I didn't even do that, just downgraded to 2.0.0 and everything seems fine.

This was referenced Sep 26, 2017
@flash23
Copy link

flash23 commented Sep 26, 2017

-(void)registerForPush
{
    UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if(granted && !error )
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] registerForRemoteNotifications];
                [UNUserNotificationCenter currentNotificationCenter].delegate = self;
                
                [[PushManager sharedInstance] registerNotificationCategories];
                
                if([FIRApp defaultApp] == nil)
                {
                    [FIRApp configure];
                }
                [FIRMessaging messaging].delegate = self;
                
                DDLogDebug( @"Push registration success." );
            });
        }
        else
        {
            DDLogDebug( @"Push registration FAILED" );
        }
    }];
}

this worked for me ios11, xcode 9, firebase 4.2, firemessaging... 2.0.3
Even if I dont do it immediately... dont call this on first lunch(kill the app after first lunch)

Just dont call [FIRApp configure]; before [[UIApplication sharedApplication] registerForRemoteNotifications];

@leaninsights
Copy link

leaninsights commented Sep 28, 2017

[SOLVED]
Was able to solve the problem, I forgot to add:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken }

========
I am new to commenting on Github, so please excuse any newbie mistakes.

I am experiencing the same problem running Xcode 9. Just updated to Firebase pod v4.2.0 and forcing FirebaseInstanceId to v2.0.0

I followed Tom Kerpelman's article (https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html) and get to where I send a curl request to FCM and get the multicast 'Success' message back in the terminal.

Request
curl --header "Content-Type: application/json" \ --header "Authorization: key=AAAA...my_server_key...Yvtk8UR" \ https://fcm.googleapis.com/fcm/send \ -d '{"notification": {"body": "Hello from curl via FCM!", "sound": "default"}, "priority": "high", "to": "d2FIEp-BpTg:APA91bGo_hvwvLw-z...my_fcm_token...V-zr9MPUYMT"}'

Response
{"multicast_id":9208728090202853353,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1506630341902123%a15af8c5a15af8c5"}]}

However, it does not show up on my device. The test through Apple's API works fine on the same device. Using Firebase's Notification function in the Console does not work neither when sending to the app as to a single device (using a valid FCM Token).

My podfile:
platform :ios, '10.3'
pod 'Firebase/Core', '4.2.0'
pod 'Firebase/Analytics'
pod 'Firebase/Auth'
pod 'Firebase/Crash'
pod 'Firebase/Database'
pod 'Firebase/Messaging', '4.2.0'
pod 'Firebase/Performance'
pod 'FirebaseInstanceID', '2.0.0'
pod 'Firebase/RemoteConfig'
pod 'Firebase/Storage'
pod 'SwiftMessages'
pod 'SDWebImage', '~> 4.0'

I am also firing application.registerForRemoteNotifications() before I fire FirebaseApp.configure() in didFinishLaunchingWithOptions

Any advice would be welcome. It all worked in a previous app built using Xcode 8.

@plu
Copy link

plu commented Oct 1, 2017

I didn't even do that, just downgraded to 2.0.0 and everything seems fine.

While my tests on both of my devices here were working fine fine, I have now one user reporting that push notifications are not working at all. As it's only one user, I don't want to draw any conclusions just yet. Still thought it's worth mentioning it here.

Any ETA on when a fix will be released for this issue?

@paulb777
Copy link
Member

paulb777 commented Oct 3, 2017

Fix released today in Firebase 4.3.0, FirebaseMessaging 2.0.4, and FirebaseInstanceID 2.0.4

@paulb777 paulb777 closed this as completed Oct 3, 2017
@plu
Copy link

plu commented Oct 4, 2017

Awesome, thank you!

@pfrischmuth
Copy link
Author

The latest release fixes the issue for us. Thank you! 👍

@ashok1089
Copy link

@ChrisRicca how were you able to solve your issue "Unregistered Registration Token".

@geraldeersteling
Copy link

geraldeersteling commented Apr 25, 2018

I'm still getting the issue with Firebase 4.13.0, Messaging 2.2.0 and InstanceID 2.0.10. Just like @ashok1089; how do I fix the 'Unregistered Registration Token' error from the CM Console?

What I tried and what failed:

  • adding application.registerForRemoteNotifications() before configuring Firebase
  • downgrading to InstanceID 2.0.0

My original setup was setting the token received in didRegisterForRemoteNotificationsWithDeviceToken to Messaging.messaging().setAPNSToken(), this worked for a while but now I suddenly get the unregistered device token failure when trying to send a test message through the CM Console

I disabled method swizzling btw if it matters


To elaborate even more; I followed this blog post and verified that sending a message directly through APNs works (as in I receive the push message on my device).
However, in the same blog post, I try to use FCM I get the following response:

{"multicast_id":MY_ID_HERE,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"}]}

I've got no clue now anymore.


Ok...everything works again. And I've got no clue why, and I'm not sure if it will keep working with all the troubles I've had.
Anyway for the unfortunate readers; here's what my configuration looks like now:

  • Used all recent pods, except for FirebaseInstanceID which is set on 2.0.0
  • At some point in the tutorials, they instruct you to do all the UNNotificationCenter authorization and application.registerForRemoteNotifications(). I did all those things before setting up Firebase (calling Firebase's configure with whatever configuration you use) and assigning Messaging's delegate
  • After the UNNotificationCenter setup finishes, I did the Firebase setup

Now where does this differ? Here are a few pointers which 'may' help:

  • If you subscribe to topics; I subscribe to topics whenever I receive a new fcmToken in Messaging's delegate method, this is the only place I'm now certain I can "safely" do it (on the main thread of course)
  • Keep sending whatever token you receive in Messaging's delegate method to your server...better to be a call to many then one too few...

With the above things it now somehow works, but as I said before. No. Clue. Why.

@firebase firebase locked and limited conversation to collaborators Nov 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests