Related
I discovered an issue with my application, certain users stopped receiving push notifications for awhile. Their FCM token that is associated with their account seems to either have expired or they need a new one. I tested by deleting the app on my device and I was issued a new fcm token in Xcode.
I copied that FCM token from the Xcode console and manually replaced it with the one I had in Firebase database, I then was able to successfully receive push notifications.
My question, is it possible to renew current users FCM token when they sign back into/ or open the app again so they can receive push notifications successfully?
Here is my app delegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
attemptRegisterForNotifications(application: application)
Messaging.messaging().delegate = self
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Registered for notifications", deviceToken)
Messaging.messaging().apnsToken = deviceToken
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Registered with FCM with token:", fcmToken)
}
// Listen for user notifcations
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
private func attemptRegisterForNotifications(application: UIApplication) {
print("Attempting to register APNS...")
UNUserNotificationCenter.current().delegate = self
let options: UNAuthorizationOptions = [.alert, . badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: options) { (granted, error) in
if let error = error {
print("Failed to request auth:", error)
return
}
if granted {
print("Auth granted.")
} else {
print("Auth denied")
}
}
application.registerForRemoteNotifications()
}
You don't need to manually "renew" a device token (in fact, there's no way to force that). Instead, you should expect that the device token can change at any time. Because your app might unexpectedly get a new token, you should record that token for the user every time your app launches. The old token will no longer work, and your server code should check for failure in order to know when it's time to remove it.
You want to use the Firebase Messaging delegate FIRMessagingDelegate to handle updates to the FCM token. Ideally, you want to handle this on app launch, so consider doing this in the App Delegate:
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Messaging.messaging().delegate = self
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
if let userId = Auth.auth().currentUser?.uid { // user is signed in
Firestore.firestore().collection("userProfiles").document(userId).updateData(["fcmToken": fcmToken]) { (error) in
if let error = error {
print(error)
}
}
}
}
}
You need to update your users token in your servers database in every app launch, so you always have the latest token.
You would have to manage what user is associated to the token yourself. When the user signs in you should associate the token with the user's ID and when the user signs out you should remove that association.
I am currently trying to get a push message. However, you cannot receive a push message. What am I missing?
AppDelegate
import UIKit
import UserNotifications
import Firebase
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
// Override point for customization after application launch.
//create the notificationCenter
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
Messaging.messaging().delegate = self
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map{ String(format: "%02x", $0) }.joined()
Log.Info("Registration succeeded!")
Log.Info("Token: \(token)")
LocalStorage.set(token, "dacDeviceToken")
Messaging.messaging().apnsToken = deviceToken
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
Log.Error("Error fetching remote instance ID: \(error)")
} else if let result = result {
Log.Info("Remote instance ID token: \(result.token)")
}
}
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
Log.Warning("Registration failed!")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo["gcmMessageIDKey"] {
Log.Info("Message ID: \(messageID)")
}
// Print full message.
Log.Info(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo["gcmMessageIDKey"] {
Log.Info("Message ID: \(messageID)")
}
// Print full message.
Log.Info(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
}
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// Print message ID.
Log.Info("Message ID: \(userInfo["gcm.message_id"]!)")
// Print full message.
print("%#", userInfo)
Log.Info(userInfo)
}
}
extension AppDelegate : MessagingDelegate {
// Receive data message on iOS 10 devices.
func applicationReceivedRemoteMessage(_ remoteMessage: MessagingRemoteMessage) {
print("%#", remoteMessage.appData)
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
Log.Info("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
}
my Log
2019-09-24 19:31:46.519806+0900 test[586:74065] -
[I-ACS036002] Analytics screen reporting is enabled.
Call +[FIRAnalytics setScreenName:setScreenClass:] to set the screen
name or override the default screen class name. To disable screen
reporting, set the flag FirebaseScreenReportingEnabled to NO (boolean)
in the Info.plist 2019-09-24 19:31:46.756433+0900 test[586:74071]
6.9.0 - [Firebase/Messaging][I-FCM001000] FIRMessaging Remote Notifications proxy enabled, will swizzle remote notification receiver
handlers. If you'd prefer to manually integrate Firebase Messaging,
add "FirebaseAppDelegateProxyEnabled" to your Info.plist, and set it
to NO. Follow the instructions at:
to ensure proper integration. 2019-09-24 19:31:46.759687+0900
test[586:74071] 6.9.0 - [Firebase/Analytics][I-ACS023007] Analytics
v.60102000 started 2019-09-24 19:31:46.760699+0900 test[586:74071]
6.9.0 - [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled INFO: 2019-09-24 10:31:46 +0000 -
AppDelegate.swift messaging(_:didReceiveRegistrationToken:) [Line:196]
Firebase registration token:
dZ4US-5dJqk:APA91bF0-****************
INFO: 2019-09-24 10:31:46 +0000 - AppDelegate.swift
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
[Line:82] Registration succeeded! INFO: 2019-09-24 10:31:46 +0000 -
AppDelegate.swift
application(:didRegisterForRemoteNotificationsWithDeviceToken:)
[Line:83] Token:
213eba827****************************** INFO:
2019-09-24 10:31:46 +0000 - AppDelegate.swift
application(:didRegisterForRemoteNotificationsWithDeviceToken:)
[Line:90] Remote instance ID token:
dZ4US-5dJqk:APA91bF0-77***********
2019-09-24 19:31:46.921546+0900 test[586:74071] [MC] System group
container for systemgroup.com.apple.configurationprofiles path is
/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2019-09-24 19:31:46.923537+0900 test[586:74071] [MC] Reading from
public effective user settings.
Send Test FCM
I don't get anything. My app doesn't receive push messages whether it's in the foreground or in the background.
Please help me a lot.
The token you added in the figure is the device token value. Token values are visible in the log.
EDIT
I saw the answer and followed it, but it doesn't work.
Can you Put GoogleService-Info.plist file in your project?
Try This In My Code 100% Working
import Firebase
import FirebaseCore
import FirebaseMessaging
import UserNotifications
import UserNotificationsUI
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate , MessagingDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Messaging.messaging().delegate = self
FirebaseApp.configure()
//Register App For Push Notification
self.registerAppForPushNotificaition()
application.registerForRemoteNotifications()
return true
}
func registerAppForPushNotificaition(){
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
let inviteCategory = UNNotificationCategory(identifier: "Notification", actions: [], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
let categories = NSSet(objects: inviteCategory)
center.delegate = self
center.setNotificationCategories(categories as! Set<UNNotificationCategory>)
center.requestAuthorization(options: [.sound, .badge, .alert], completionHandler: { (granted, error) in
if !(error != nil){
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
})
} else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types:[.sound , .alert , .badge] , categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler(.alert)
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenType.sandbox)
Messaging.messaging().apnsToken = deviceToken
let token = InstanceID.instanceID().token()
if token != nil {
fcmID = token!
}
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
// print(deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NSLog("Failed to get Access Token: \(error)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if Auth.auth().canHandleNotification(userInfo) {
completionHandler(UIBackgroundFetchResult.noData)
return
}
completionHandler(UIBackgroundFetchResult.newData)
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("fcmToken \(fcmToken)")
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("remort \(remoteMessage.appData)")
}
I saw the answer and followed it, but it doesn't work. However, when you added a new project on the Fire Base, added the iOS app again, and tried, it was successful. I'm not sure what's wrong. Was that a problem with my code?I thought, but when I used the code in the question,also it worked. I simply created and added a new project for my solution.
I develop the app into webview. and configured firebase push notification successfully. messages are delivering fine.
But Now I want Device token into URL. by which I can send msg according to the token.
I write this code in Appdelegate.swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map {String (format: "%02.2hhx", $0)}.joined()
print("Token : \(token)")
let preferences = UserDefaults.standard
preferences.setValue(token, forKey: "token")
preferences.synchronize()
}
//Changes
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError
error: Error) {
// Try again later.
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
//Saving fcmToken to pass to the url
//Bhaskar Changes
let preferences = UserDefaults.standard
preferences.setValue(fcmToken, forKey: "token")
preferences.synchronize()
let token = Messaging.messaging().fcmToken
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Message Data", remoteMessage.appData)
}
and this code in Viewcontroller.swift
override func viewDidLoad() {
super.viewDidLoad()
//Retrieving the fcmToken
let prefs = UserDefaults.standard
let token = prefs.string(forKey: "token")
//?token= \(token as Optional)&device=ios
print("Token accessed : \(String(describing: token))")
webView.load(URLRequest(url: URL(string: "https://instaglamexpress.com/app/customer/?device=ios&token=\(String(describing: token))")!))
}
But everytime when I run the program. token is not storing into the token variable. it is showing "nil".
Am I following the right procedure.??
Please help me with the actual solution.
Maybe you forget to add Messaging.messaging().delegate = self in this way func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) will never be called.
I am setting up push notifications, and everything is going well until I try to get the FCM token so I can send a test message to an actual device. Using the pods Firebase 5.8.0, FirebaseCore (5.1.3), FirebaseInstanceID (3.2.1), and FirebaseMessaging (3.1.2), I can get the APNS token fine but every time I try to get the FCM token, it comes out as nil or when I use InstanceID.instanceID().instanceID(handler:) it results in some timeout error code 1003 and a result of nil. didReceiveRegistrationToken does not get called either. I've tried a many 2017 solutions but they're either deprecated or don't work. MessageDelegate and UNUserNotificationCenterDelegate are set, push notifications, and keychain sharing are enabled in capabilities, method swizzling is off via p-list and Here is my didRegisterForRemoteNotificationsWithDeviceToken function where I correctly get the apns token. Any ideas? Thanks.
`public func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Registration Successful: Device token \(deviceToken)")
Messaging.messaging().apnsToken = deviceToken
print("Messaging APNS Token:\(Messaging.messaging().apnsToken)")
print("Instance Id: \(InstanceID.instanceID().token())") //deprecated & returns nil
print("Messaging APNS Token:\(Messaging.messaging().apnsToken)")
print("Token:\(Messaging.messaging().fcmToken)") // return nil
InstanceID.instanceID().instanceID { (result, error) in
if let result = result {
print("Result:\(String(describing: result?.token))")
} else {
print("Error:\(error))")
} //returns after about 2 mins with an firebase iid error of 1003
}
Please check the below app delegate code.
import UIKit
import Firebase
import FirebaseMessaging
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
//REMOTE NOTIFICATION
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
let token = Messaging.messaging().fcmToken
print("FCM token: \(token ?? "")")
//Added Code to display notification when app is in Foreground
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
} else {
// Fallback on earlier versions
}
return true
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken as Data
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
// Print full message.
print(userInfo)
}
// This method will be called when app received push notifications in foreground
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([UNNotificationPresentationOptions.alert,UNNotificationPresentationOptions.sound,UNNotificationPresentationOptions.badge])
}
// MARK:- Messaging Delegates
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
InstanceID.instanceID().instanceID { (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)")
}
}
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("received remote notification")
}
}
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 my own app server.
i am wondering below which way is correct way to retrieve the registration id for the device:-
1) retrieve registration id token from didRegisterForRemoteNotificationWithDeviceToken
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var token = ""
for i in 0..<deviceToken.count {
token += String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
print("Registration succeeded!")
print("Token: ", token)
Callquery(token)
}
2) Retrieve Registration token from firebase (Based on Firebase document which retrieve the current registration token)
let token = FIRInstanceID.instanceID().token()!
i was using the first way, the push notification is not being received even the registration id is stored on my app server database accordingly and i get this CURL session result :-
{"multicast_id":6074293608087656831,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
i had also tried the second way and get fatal error while running the app as below:-
appreciated if anyone could point me the right way, thanks!
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)
The recommended way by Firebase:
let token = Messaging.messaging().fcmToken
Reference : Setting Up a Firebase Cloud Messaging Client App on iOS
Swift 3 + Firebase 4.0.4 :
static var FirebaseToken : String? {
return InstanceID.instanceID().token()
}
Swift 4 + Firebase (5.3.0)
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)")
}
})
}
Swift 4
Courtesy of: https://stackoverflow.com/a/50945350/1014164
InstanceID.instanceID().instanceID { (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)")
}
}
FCM Device Token swift3
let fcmDeviceToken = FIRInstanceID.instanceID().token()
print("FCM token: \(fcmDeviceToken ?? "")")
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
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()
}
To Get current FCM Token
if let token = Messaging.messaging().fcmToken {
// token is current fcmToken
}
To Renew current FCM Token
If we delete current instanceId, new token will be received vi MessagingDelegate (messaging:didReceiveRegistrationToken) a moment later.
InstanceID.instanceID().deleteID { (error) in
if let er = error {
print(er.localizedDescription)
} else {
print("instanceID().deleteID success ---------------➤")
}
}
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
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:
Enable push notification from capability section of xcode.
check twice your both p12 certificates uploaded on firebase project setting.
Device token only can get from real device not a simulator.
First of all, you should import all required libs
import Firebase
import UserNotifications
later in AppDelegate.swift call next function
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instance ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
}
}
confirm to MessagingDelegate protocol.
then you can add below delegate method and get the Firebase Token. (documentation https://firebase.google.com/docs/cloud-messaging/ios/client )
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
// send to remote server
InstanceID.instanceID().instanceID { result, error in
if let error = error {
print("Error fetching remote instance ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
}
}
This question is old but still if someone want to use in Objective C.
Latest Firebase: 6.27.0
In iOS Objective C we can use like this
[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Error : %#", error);
} else {
token = result.token;
}
NSLog(#"Token %#", result.token);
}];
and to get Instance Id:
[[FIRInstanceID instanceID] getIDWithHandler:^(NSString *identity, NSError *error) {
if (error != nil) {
NSLog(#"Error : %#", error);
} else {
NSLog(#"instance ID: %#", identity);
}
NSLog(#"IID %#", identity);
}];
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
let deviceTokenString = deviceToken.reduce("") { $0 + String(format: "%02X", $1) }
print("APNs device token: \(deviceTokenString)"
}