50

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:- enter image description here

appreciated if anyone could point me the right way, thanks!

aznelite89
  • 2,025
  • 4
  • 21
  • 32
  • see this once it helps you http://stackoverflow.com/questions/37667753/ios-firebase-push-notifications-how-to-give-firebase-users-device-token-and-s – Anbu.Karthik Oct 13 '16 at 07:39
  • Note: the deviceToken parameter in didRegisterForRemoteNotificationWithDeviceToken is NOT the Firebase registration token. You still need to call return InstanceID.instanceID().token() as explained below. – William T. Mallard Nov 17 '18 at 02:26

15 Answers15

56

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)

Naveed Ahmad
  • 6,627
  • 2
  • 58
  • 83
Sam
  • 5,375
  • 2
  • 45
  • 54
  • hi, how to post request token ? – Girl_engineer Apr 19 '18 at 11:09
  • 2
    In case anybody did what I did, the deviceToken:Data parameter is NOT the FCM registration token. The token from InstanceID().token() IS. – William T. Mallard Nov 17 '18 at 02:21
  • I get 'token()' is deprecated: Use instanceIDWithHandler: instead. for token() –  May 27 '19 at 02:16
  • 1
    I did this instead: InstanceID.instanceID().instanceID { (result, error) in if error == nil { print("InstanceID token: \(result)") } else { print(error, ": Error in getting token for Fire") } } –  May 27 '19 at 02:20
  • What about [this](https://firebase.google.com/docs/cloud-messaging/ios/client)? Registration tokens are delivered via the method `messaging:didReceiveRegistrationToken:`. This method is called generally once per app start with registration token. – Parth Jan 31 '21 at 17:37
44

The recommended way by Firebase:

let token = Messaging.messaging().fcmToken

Reference : Setting Up a Firebase Cloud Messaging Client App on iOS

Musa almatri
  • 5,596
  • 2
  • 34
  • 33
24

Swift 3 + Firebase 4.0.4 :

static var FirebaseToken : String? {
    return InstanceID.instanceID().token()
}
Community
  • 1
  • 1
MBH
  • 16,271
  • 19
  • 99
  • 149
  • 4
    Just for clarification; what is the difference between yours and the answer below (`Messaging.messaging().fcmToken`)? @MBH – j3141592653589793238 May 13 '18 at 16:18
  • https://stackoverflow.com/questions/44615817/what-is-the-difference-between-firinstanceid-instanceid-token-and-messaging – hmlasnk Mar 10 '20 at 14:55
21

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)")
        }
    })
}
Daniyal Raza
  • 352
  • 3
  • 13
8

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)")
    }
}
cohen72
  • 2,830
  • 29
  • 44
  • i got "Static member 'instanceID' cannot be used " when called in the homescreen viewdidload, **can u help?** – kemdo Jul 16 '18 at 09:41
  • @kemdo make sure you're writing `InstanceID.instanceID().instanceID` with the parenthesis and not `InstanceID.instanceID.instanceID` – cohen72 Jul 17 '18 at 07:17
  • @kemdo , Yocoh , How did you solve this when i get Static member 'instanceID...... issue ? – Jamshed Alam Aug 27 '18 at 07:30
6

FCM Device Token swift3

    let fcmDeviceToken = FIRInstanceID.instanceID().token()
    print("FCM token: \(fcmDeviceToken ?? "")")
jazzbpn
  • 6,441
  • 16
  • 63
  • 99
5

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

John Leonardo
  • 598
  • 3
  • 23
5

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()
}
Jake Lee
  • 7,549
  • 8
  • 45
  • 86
Naveen Ramanathan
  • 2,166
  • 1
  • 19
  • 21
5

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 ---------------➤")
    }
}
Brownsoo Han
  • 4,549
  • 3
  • 20
  • 20
2

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

erickva
  • 513
  • 6
  • 17
1

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.

Emil
  • 7,220
  • 17
  • 76
  • 135
Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52
0

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)")
        }
    }
}
0

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)")
            }
        }
    }
zdravko zdravkin
  • 2,090
  • 19
  • 21
0

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);
       }];
Malik
  • 181
  • 8
-4
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)"
}
Pathak Ayush
  • 726
  • 12
  • 24
Kent Chong
  • 79
  • 6