i had implement Firebase with FirebaseAuth/FCM etc and did sent notification successfully through Firebase Console.
However i would need to push the notification from m
First register for the firebase token refresh notification:
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name:
NSNotification.Name.InstanceIDTokenRefresh, object: nil)
Then you can receive the token in the tokenRefreshNotification selector:
func tokenRefreshNotification(_ notification: Notification) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
I was having the same problem, but could not figure out what was going on.
The didRegisterForRemoteNotificationsWithDeviceToken
suggested by @Sam is called (almost) every time, so it is a good work around. BUT, it is NOT called the first time you open the app with the refreshed token.
So for this scenario you still need the:
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Refreshed Token: \(fcmToken)")
}
So if you only use the:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let fcmToken = InstanceID.instanceID().token() {
print("InstanceID token: \(fcmToken)")
}
}
You will only get the "refreshed token" the second time the user opens the app.
I managed to force a refresh token by uninstalling the app and cleaning the Build Folder (Product > Clean Build Folder). Good for testing.
Ideally it could all be handled at messaging:didReceiveRegistrationToken
delegate method, but I was not able to make it work. Another way to get notified for changes in the FCM token is to listen NSNotification
named kFIRMessagingRegistrationTokenRefreshNotification
as suggested in the documentation: https://firebase.google.com/docs/cloud-messaging/ios/client
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
InstanceID.instanceID().instanceID(handler: { (result, error) in
if let error = error {
print("Error fetching remote instange ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
})
}
The tokenRefreshNotification
function doesn't always get called when launching the app.
However, when placing the code inside the regular didRegisterForRemoteNotificationsWithDeviceToken
delegate function, I can get the token every time:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let refreshedToken = InstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
}
}
(Swift 3 + Firebase 4.0.4)
First import the libraries like:
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications
set Delegate:MessagingDelegate, UNUserNotificationCenterDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
Write this code on didFinishLaunching():
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
Messaging.messaging().delegate = self
//remote Notifications
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (isGranted, err) in
if err != nil {
//Something bad happend
} else {
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
} else {
// Fallback on earlier versions
}
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.badge,.sound,.alert], completionHandler: { (granted, error) in
application.registerForRemoteNotifications()
})
}else{
let notificationSettings = UIUserNotificationSettings(types: [.badge,.sound,.alert], categories: nil)
UIApplication.shared.registerUserNotificationSettings(notificationSettings)
UIApplication.shared.registerForRemoteNotifications()
}
return true
}
Write connectFCM method like this way:
func ConnectToFCM() {
Messaging.messaging().shouldEstablishDirectChannel = true
if let token = InstanceID.instanceID().token() {
print("\n\n\n\n\n\n\n\n\n\n ====== TOKEN DCS: " + token)
}
Also write delegate methods for registering and receiving push notification:
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("\n\n\n\n\n ==== FCM Token: ",fcmToken)
HelperFunction.helper.storeInUserDefaultForKey(name: kFCMToken, val: fcmToken)
ConnectToFCM()
}
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// UIApplication.shared.applicationIconBadgeNumber += 1
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Barker"), object: nil)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
}
Now we can test it from firebase console.
100% working, easy and tested
Note: 1) Enable push notification from capability section of xcode.
2) check twice your both p12 certificates uploaded on firebase project setting.
3) Device token only can get from real device not a simulator.
Go with the second option, and this is going to seem really stupid/simple, but to fix that nil optional fatal error, just remove the force-unwrap at the end
Your code:
var token = FIRInstanceID.instanceID().token()!
Make it:
var token = FIRInstanceID.instanceID().token()
That will at least fix that nasty crash