I followed the tutorial by google on https://firebase.google.com/docs/notifications/ios/console-topics#receive_and_handle_topic_messages to subscribe to a Firebase topic on my iOS app.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
FIRMessaging.messaging().subscribeToTopic("/topics/Notifications")
let homeViewController = UINavigationController(rootViewController: HomeViewController())
UINavigationBar.appearance().translucent = false
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = homeViewController
window?.makeKeyAndVisible()
return true
}
However, when I send a topic push notification out from the Firebase console. I could not receive any push notifications. But when I send out push notification to user segment from the console, the push is working perfectly. When I check the Xcode console, I am seeing this FIRMessaging error.
2016-05-31 11:11:47.893: <FIRMessaging/WARNING> Cannot subscribe to topic: /topics/Notifications with token: (null)
I've tried to search for this error but have no luck finding anything. I am not sure if this is the problem that is causing my app to not receive any push from topics.
Does anyone have this issue and know how to solve it?
Looks like maybe you're calling subscribeToTopic
too early.
First, before you set up any Firebase call, make sure you call
FIRApp.configure()
That will ensure that all Firebase services are properly set up and initialized.
Next, you're going to need to wait just a bit to subscribe to topics. Your client needs to first register your app with both APNs and FCM to ensure that it can receive notifications. That involves a network call, which means you can't subscribe to topics when your app first launches.
Instead, I'd recommend putting that code into your application:didRegisterUserNotificationSettings
handler instead. Something like this:
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
NSLog(@"Hooray! I'm registered!");
[[FIRMessaging messaging] subscribeToTopic:@"/topics/cool_users"];
}
Edit: And the Swift version...
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
print("Hooray! I'm registered!")
FIRMessaging.messaging().subscribeToTopic("/topics/swift_fans")
}
The accepted solution did not work for me. The token is not always available when application:didRegisterUserNotificationSettings:
is called.
For example if application is freshly installed and starts for the first time FIRInstanceID.instanceID().token()
returns nil.
You need to make sure application calls subscribeToTopic:
after the token is available.
I ended up with creating a helper object that enqueues subscribeToTopic:
, unsubscribeFrom:
calls and executes them in FIFO order after the token arrives.
class FIRMessagingHelper {
private let queue: OperationQueue
init() {
queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.addOperation(TokenReadyOperation())
}
func subscribeTo(topic: String) {
queue.addOperation {
OperationQueue.main.addOperation({
FIRMessaging.messaging().subscribeToTopic(topic)
})
}
}
func unsubscribeFrom(topic: String) {
queue.addOperation {
OperationQueue.main.addOperation({
FIRMessaging.messaging().unsubscribeFromTopic(topic)
})
}
}
}
TokenReadyOperation waits until the token appears. AsynchronousOperation is used as the base class to minimize boilerplate.
class TokenReadyOperation : AsynchronousOperation {
override init() {
super.init()
NotificationCenter.default.addObserver(self,
selector: #selector(TokenReadyOperation.tokenRefreshed(notification:)),
name: .firInstanceIDTokenRefresh,
object: nil)
}
override func didStart() {
finishIfTokenAvailable()
}
private func finishIfTokenAvailable() {
guard FIRInstanceID.instanceID().token() != nil else { return }
markFinished()
}
/// Posted every time token changes
@objc private func tokenRefreshed(notification: Notification) {
finishIfTokenAvailable()
}
}
Few things to keep in mind:
- App must call
FIRApp.configure()
or FIRApp.configureWithOptions(_:)
prior making any Firebase calls (as Todd Kerpelman mentioned)
subscribeToTopic:
, unsubscribeFrom:
are not thread safe and must be executed on main thread
- Topic names has to be in "/topics/*" format (as henmer mentioned)
- Make sure to use different configuration plist for debug and App Store release of your app. See
FIRApp.configureWithOptions(_:)
documentation.
- Date & Time should be current, otherwise the token may not be delivered.
- Make sure to use the newest framework version. I had issues with notification delivery with the SDK released around January 2017.
My problem was not solved by calling subscribeToTopic
after
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
instead it worked by calling subscribeToTopic
after
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
this function get called when you get your push token from APNS not firebase.
Xcode 8.3.2
Swift 3.0