Create a new project as described in https://firebase.google.com/docs/cloud-messaging/ios/client. Notably, don't set up a direct channel; and don't enable silent background notifications.
Try to subscribe to a topic on first app start after permissions are granted. Subscription will fail with error code 501 (kFIRMessagingErrorCodeMissingDeviceID). If logging is enabled, "Device check in error, no auth credentials found" is printed before.
(Tested on iOS 11.4 device.)
Use Messaging_Sample_iOS slightly modified by me here: https://github.com/herrernst/firebase-ios-sdk/tree/subscribing-bug.
Add a GoogleService-Info.plist. On first app start (remove app before trying again), click "Request User Notifications". The completion block of subscribeToTopic will be called with an error. (You can probably ignore the thread checker warnings complaining about UI updates from background threads.)
You won't be able to subscribe successfully before the FCM token is first fetched. In your example, this code should be moved to your implementation of this MessagingDelegate method.
Thank you. But why does it work when a direct channel setup is requested, or when silent background notifications are enabled?
IIRC requesting notification permissions via registerForRemoteNotifications affects the IID fetch process, but I'm fuzzy on the details. @chliangGoogle can probably answer in more detail.
Also, the documentation you linked about -messaging:didReceiveRegistrationToken: says: "Typically it will be called once per app start, but may be called more often." But what if I want to subscribe to a topic later on, when the delegate method has already been called?
In other words, how do I know if I will be able to successfully subscribe to a topic, or if a have to wait for -messaging:didReceiveRegistrationToken:?
I can't reproduce the error you had by calling subscription too early or without any checkin credentials. Seem like your client's direct channel credentials are corrupted for some reason.
With the latest FCM (v3.0.3) your subscription should suspend without a token. Regardless of MCS connection or background notification. And Firebase do request a token during initialization(if you didn't disable auto init flag), and as long as you put subscription in the code Morgan suggested, should be working for you.
If you continue to see kFIRMessagingErrorCodeMissingDeviceID error after the suggested fix, please file me a bug on this.
Actually with the latest FCM (v3.0.3) you should be able to call subscription any time and the operation will simply suspend if a token is not present. And the operation resumes any time a token is retrieved and your subscription can then complete.
Can you try with the latest fcm and send us debug log if you still encounter the issue? Make sure you add -FIRDebugEnabled to expand the debug logs.
@chliangGoogle
Seem like your client's direct channel credentials are corrupted for some reason.
As I've said, I did not set up a direct channel.
Also, as I've mentioned, I'm already using the latest FCM (3.0.3), and my example is based on it, too. Of course I can send you the debug (next week), but you should be able to try it out yourself by running my example.
And the operation resumes any time a token is retrieved and your subscription can then complete.
Is there any notification posted or callback called when such a suspended subscription completes? Or can I query FCM which topics are successfully registered? I want to show the user feedback about the (successfully) registered topics.
Your direct channel credentials is generated and used for token generation, regardless you are setting it up or not.
When the suspended subscription completes, it goes back to the same callback for your original subscription request.
Ok, I've now looked at it a little bit more and added some more logging to the test case at https://github.com/herrernst/firebase-ios-sdk/tree/subscribing-bug.
When running the example app at first time, these things happen in order:
didReceiveRegistrationToken is called with an FCM tokendidReceiveRegistrationToken is NOT called anymore, so there's no point in putting the topic subscription there as it won't be called.Note that subscribing will work at the second app start, even if I do nothing (i.e. not click the button) on the first app start.
Here's the debug log, I've redacted possible sensitive data: https://pastebin.com/raw/sNqUgiPf
So, again, if this is by design, I still don't know when and how to successfully subscribe to a topic on first app start.
When the suspended subscription completes, it goes back to the same callback for your original subscription request.
What callback do you mean? The completion block of subscribeToTopic? Because I never see that one getting called later if it was called with an error before.
You are right, you should be able to call subscription any where not necessary inside the callback.
When subscription failed, the error (501) returns in the completion block. This is the case happened to you. So even if you get a token later, the completion block will not be triggered again since it's already returned with an error.
And Yes I meant the completion block of subscribeToTopic.
@morganchen12 Can you reproduce the case based on developer's repo? I'm able to reproduce once but not again.
I'm able to reproduce by turn off direct channel and disable auto collection ( put FirebaseMessagingAutoInitEnabled in info.plist).
Thank you for reporting this issue, we are working on a fix for it.
@chliangGoogle Thanks for investigating this! BTW, I get this error regardless of FirebaseMessagingAutoInitEnabled being set in Info.plist
@chliangGoogle @herrernst I'm also facing this issue. Usually, I subscribe to 4 topics at some point and indeed the 1st one fails on a first launch with error code 501.
I use default values for both shouldEstablishDirectChannel and FirebaseMessagingAutoInitEnabled. In fact, I don't have such strings in my code whatsoever. Also, I use the same versions which @herrernst uses.
Let me know, if you need a debug log or something that might help.
The fix doesn't depend on the FirebaseMessagingAutoInitEnabled flag. We found out checkin is not considered valid during app first start, causing the very first call always failed. So this fix should resolve your issues.
This should be fixed in the next release; please re-open this issue if it regresses past that point.
Hello,
Thanks for the hard work!
As a piece of information, I had the same error today and fixed it by setting in plist.info
<key>FirebaseMessagingAutoInitEnabled</key>
<true/>
It used to be set to false, I guess I did some bad fiddling.
Most helpful comment
The fix doesn't depend on the FirebaseMessagingAutoInitEnabled flag. We found out checkin is not considered valid during app first start, causing the very first call always failed. So this fix should resolve your issues.
This should be fixed in the next release; please re-open this issue if it regresses past that point.