FIRInstanceID.instanceIDWithHandler() handler is not called if unregisterForRemoteNotifications() has previously been called more than once #3229
Description
- Xcode version: 10.2.1
- Firebase SDK version: 6.2.0
- Firebase Component: Messaging
- Component version: 4.0.2
[REQUIRED] Step 3: Describe the problem
The instanceIDWithHandler() method of FIRInstanceID docs say that the handler will always be called. However, seemingly if you have previously called your Application's unregisterForRemoteNotifications() twice, then the handler is never called.
This is happening in my application as I allow the user to enable/disable notifications from within the app, and if they turn them off and on a few times, the callback handler is never called and so things lock up.
The docs say that you should be able to call this at any point to get the current token, rather than storing it yourself.
(The anchor link I have used doesn't seem to work - I am referring to the "Fetching the current registration token" section)
Steps to reproduce:
I've created a simple test project which shows the problem, which is attached.
FirebaseMessagingTest.zip
- Add your own GoogleService-Info.plist, and change the Bundle Identifier accordingly.
- Run
pod install
to install the Firbase SDK via Cocoapods. - Run the app, with device attached, click the button to enable/disable notifications several times.
- Watch the Output window in Xcode for log messages: Once it goes wrong, you'll see it starts fetching the token, but never finishes.
Relevant Code:
Alternatively, below is the code (minus the delegates):
class ViewController: UIViewController {
typealias CompletionHandler = (_ success: Bool, _ error: Error?) -> Void
private var mNotificationsEnabled = false
override func viewDidLoad() {
super.viewDidLoad()
FirebaseApp.configure()
}
@IBAction func ButtonPressed(_ sender: UIButton) {
mNotificationsEnabled = !mNotificationsEnabled
let newTitle = mNotificationsEnabled ? "Disable Notifications" : "Enable Notifications"
sender.setTitle(newTitle, for: .normal)
sender.isEnabled = false
setNotifications(enabled: mNotificationsEnabled, completionHandler: { (success, error) in
sender.isEnabled = true
})
}
func setNotifications(enabled: Bool, completionHandler: @escaping CompletionHandler) {
if (enabled) {
enableNotifications(completionHandler: {(success, error) in
self.getToken(completionHandler)
})
}
else {
disableNotifications(completionHandler: completionHandler)
}
}
func enableNotifications(completionHandler: @escaping CompletionHandler) {
print("Enabling...")
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {(success, error) in
if (success) {
notificationCenter.delegate = self;
Messaging.messaging().delegate = self
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications() // Must run on main thread
print("Notifications Enabled")
completionHandler(success, error)
})
}
else {
print("Enabling failed")
completionHandler(false, error)
}
})
}
func disableNotifications(completionHandler: @escaping CompletionHandler) {
print("Disabling...")
DispatchQueue.main.async(execute: {
UIApplication.shared.unregisterForRemoteNotifications() // Must run on main thread
print("Notifications Disabled")
completionHandler(true, nil)
})
}
func getToken(_ completionHandler: @escaping CompletionHandler) {
print("Fetching Token...")
//MARK: BUG? The following never calls its handler if invoked after unregisterForRemoteNotifications() has been called twice.
InstanceID.instanceID().instanceID(handler: { (result, error) in
if let error = error {
print("Error fetching remote instance ID: \(error)")
completionHandler(false, error)
}
else if let result = result {
print("Token found")
completionHandler(true, nil)
}
})
}
}