109

It's my first time using FCM.

I download a sample from firebase/quickstart-android and I install the FCM Quickstart. But I can't get any token from the log even hit the LOG TOKEN button in the app.

Then I try to send a message with Firebase console and set to target my app package name. I got incoming messages.

I want to know can FCM be used?GCM everything is ok.

Solution:

Because I am not an Android developer, just a backend developer. So it takes me some time to solve it. In my opinion, there`re some bugs in the sample app.

enter image description here

Code:

RegistrationIntentService.java

public class RegistrationIntentService extends IntentService {

    private static final String TAG = "RegIntentService";


    public RegistrationIntentService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String token = FirebaseInstanceId.getInstance().getToken();
        Log.i(TAG, "FCM Registration Token: " + token);
    }
}

MyFirebaseInstanceIDService.java

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
//        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);
//
//        // TODO: Implement this method to send any registration to your app's servers.
//        sendRegistrationToServer(refreshedToken);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     * <p>
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // Add custom implementation, as needed.
    }
}

Add this in the MainActivity.java.

 Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);

After do above,you get the Token in Logcat. But finally, I find a convenient way to get it.Just use debug mode to install the sample app and you can get the token when you first time to install it.

But I don't know why it can't print the log when I install it. Maybe be related to the mobile system.

And then why I can't get the Notification. FirebaseMessagingService.onMessageReceived did not call sendNotification

Emi Raz
  • 1,079
  • 1
  • 13
  • 21
wyx
  • 2,476
  • 4
  • 17
  • 37
  • if the log is hit, it would show the token with it in the sample app – Shubhank Jun 13 '16 at 10:30
  • No ,the sample app said .It will only show the token in logcat if I hit the button. But I find nothing in logcat.@ Shubhank – wyx Jun 13 '16 at 11:10
  • uncomment this lines `String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);` – Gaurav Jun 14 '16 at 07:33
  • This is deprecated, so update it from here. https://stackoverflow.com/q/51123197/7703497 – Pishang Ujeniya Mar 30 '21 at 22:34

23 Answers23

142

FASTEST AND GOOD FOR PROTOTYPE

The quick solution is to store it in sharedPrefs and add this logic to onCreate method in your MainActivity or class which is extending Application.

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(this, instanceIdResult -> {
    String newToken = instanceIdResult.getToken();
    Log.e("newToken", newToken);
    getActivity().getPreferences(Context.MODE_PRIVATE).edit().putString("fb", newToken).apply();
});

Log.d("newToken", getActivity().getPreferences(Context.MODE_PRIVATE).getString("fb", "empty :("));

CLEANER WAY

A better option is to create a service and keep inside a similar logic. Firstly create new Service

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onNewToken(String s) {
        super.onNewToken(s);
        Log.e("newToken", s);
        getSharedPreferences("_", MODE_PRIVATE).edit().putString("fb", s).apply();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
    }

    public static String getToken(Context context) {
        return context.getSharedPreferences("_", MODE_PRIVATE).getString("fb", "empty");
    }
}

And then add it to AndroidManifest file

<service
        android:name=".MyFirebaseMessagingService"
        android:stopWithTask="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
</service>

Finally, you are able to use a static method from your Service MyFirebaseMessagingService.getToken(Context);

THE FASTEST BUT DEPRECATED

Log.d("Firebase", "token "+ FirebaseInstanceId.getInstance().getToken());

It's still working when you are using older firebase library than version 17.x.x

Community
  • 1
  • 1
Eliasz Kubala
  • 3,414
  • 1
  • 18
  • 27
  • 8
    But the second approach only works until the shared preferences are cleared. What if the app data is cleared and that string value is lost? Android does not call "onNewtoken()" since there is no *new* token. But then how do we request the token? Everywhere it says "just use onNewToken()" but that method only runs when there is a *new* token. Let's say that method has already run, but we didn't bother to store the token. Later on we perform a check and see that the token is not set, what then? How do I trigger FCM to tell me the token again? – JeneralJames Apr 16 '19 at 10:33
  • https://stackoverflow.com/questions/51125169/what-to-use-now-that-firebaseinstanceid-getinstance-gettoken-is-deprecated – Ωmega May 24 '19 at 12:46
  • 1
    You can use `FirebaseInstanceId.getInstance().getInstanceId()` instead of `FirebaseInstanceId.getInstance().getToken()`, see [this answer](https://stackoverflow.com/a/51630819/1000551) – Vadim Kotov Dec 06 '19 at 16:40
  • @JeneralJames if a user clears app data, then `onNewToken` will always be triggered , from the documentation in here https://firebase.google.com/docs/cloud-messaging/android/client#sample-register – sarah Oct 04 '20 at 06:14
  • I used second solution, and added setToken() method, that I run in BaseActivity -> onCreate(). – George May 04 '21 at 08:42
30

The Complete Solution


The team behind Firebase Android SDK change API a little bit. I've implemented "Token to Server" logic like this:

In my instance of FirebaseMessagingService:

public class FirebaseCloudMessagingService extends FirebaseMessagingService {

    ...

    @Override
    public void onNewToken(String token) {
        // sending token to server here
    }

    ...

}

Keep in mind that token is per device, and it can be updated by Firebase regardless of your login logic. So, if you have Login and Logout functionality, you have to consider extra cases:

  1. When a new user logs in, you need to bind token to the new user (send it to the server). Because token might be updated during the session of old user and server doesn't know token of the new user.
  2. When the user logs out, you need to unbind token. Because user should not receive notifications/messages anymore.

Using new API, you can get token like this:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
        @Override
        public void onSuccess(InstanceIdResult instanceIdResult) {
            String token = instanceIdResult.getToken();
            // send it to server
        }
    });

Good luck!

rzaaeeff
  • 790
  • 1
  • 9
  • 18
  • Trying to get the value outside OnSuccess is giving null. – DragonFire Apr 02 '19 at 07:46
  • Login/logout functionality doesn't have anything to do with Push messages, this is a specific business use-case. For example, you might want to target logged out users with some marketing/promo notifications to get them to log back into the app, in which case you'll need the FCM token. But the answer is correct in terms of getting the token. – milosmns Jan 01 '20 at 15:56
  • @milosmns, you are right in terms of marketing/promo notifications. Still there is a need for an indication of token status. The simple solution would be to store the unbound tokens in some kind of history table and then use those past tokens to encourage the use to log back in. – rzaaeeff Jan 07 '20 at 07:12
  • Hm I'm not sure actually how long you can re-use the same token and when exactly it gets invalidated. This is worth investigating, as I guess you'd need to clear this history/cache/persistence table once tokens become invalid. – milosmns Jan 07 '20 at 13:12
  • @milosmns, in Firebaseland, tokens do not expire but rather get renewed. When you trigger any token related activity with FCM API, provided token is validated. If the token is invalid, you will receive error:MissingRegistration or error:InvalidRegistration. You can find more error codes here: https://firebase.google.com/docs/cloud-messaging/http-server-ref#error-codes – rzaaeeff Jan 28 '20 at 09:24
24

Important information.

if google play service hung or not running, then fcm return token = null

If play service working properly then FirebaseInstanceId.getInstance().getToken() method returns token

Log.d("FCMToken", "token "+ FirebaseInstanceId.getInstance().getToken());
Yogesh Rathi
  • 5,684
  • 4
  • 42
  • 71
  • Yes, But this happens very often – Hoang Duc Tuan Jun 05 '17 at 01:58
  • Token is cached (in-mem most likely) after it has been fetched once. So this means that you need to fetch it once or get Firebase to re-issue another token for you somehow. See here for how to fetch manually https://stackoverflow.com/a/51630819/2102748 – milosmns Jan 01 '20 at 16:05
14

FirebaseInstanceId class and it's method getInstanceId are also deprecated. So you have to use FirebaseMessaging class and it's getToken method instead.

FirebaseMessaging.getInstance().getToken().addOnSuccessListener(token -> {
        if (!TextUtils.isEmpty(token)) {
            Log.d(TAG, "retrieve token successful : " + token);
        } else{
            Log.w(TAG, "token should not be null...");
        }
    }).addOnFailureListener(e -> {
        //handle e
    }).addOnCanceledListener(() -> {
        //handle cancel
    }).addOnCompleteListener(task -> Log.v(TAG, "This is the token : " + task.getResult()));

The method getToken() is deprecated. You can use getInstanceId() instead.

If you want to handle results when requesting instanceId(token), check this code.

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
        if (instanceIdResult != null) {
            String token = instanceIdResult.getToken();
            if (!TextUtils.isEmpty(token)) {
                Log.d(TAG, "retrieve token successful : " + token);
            }
        } else{
            Log.w(TAG, "instanceIdResult should not be null..");
        }
    }).addOnFailureListener(e -> {
        //do something with e
    }).addOnCanceledListener(() -> {
        //request has canceled
    }).addOnCompleteListener(task -> Log.v(TAG, "task result : " + task.getResult().getToken()));
pw2
  • 199
  • 1
  • 8
sNash
  • 633
  • 6
  • 11
13

According to doc

Migrate a GCM client app to FCM

onTokenRefresh()

only Called if InstanceID token is updated

So it will call only at first time when you install an app to your device.

So I suggest please uninstall your app manually and try to run again

definitely you will get TOKEN

Gaurav
  • 3,213
  • 2
  • 25
  • 41
9

Try this. Why are you using RegistrationIntentService ?

public class FirebaseInstanceIDService extends FirebaseInstanceIdService {    
    @Override
    public void onTokenRefresh() {    
        String token = FirebaseInstanceId.getInstance().getToken();    
        registerToken(token);
    }

    private void registerToken(String token) {

    }
}
activesince93
  • 1,651
  • 15
  • 36
FireUser
  • 153
  • 3
  • 12
9

This line should get you the firebase FCM token.

String token = FirebaseInstanceId.getInstance().getToken();
Log.d("MYTAG", "This is your Firebase token" + token);

Do Log.d to print it out to the android monitor.

Jay Rathod RJ
  • 10,321
  • 5
  • 27
  • 49
Alphonsus Chen
  • 103
  • 1
  • 7
7

Instead of this:

    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
//        Get updated InstanceID token.
//        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);
//
//        TODO: Implement this method to send any registration to your app's servers.
//        sendRegistrationToServer(refreshedToken);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
    // [END refresh_token]

Do this:

    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // Implement this method to send token to your app's server
       sendRegistrationToServer(refreshedToken);

    }
    // [END refresh_token]

And one more thing:

You need to call sendRegistrationToServer() method which will update token on server, if you are sending push notifications from server.

UPDATE:

New Firebase token is generated (onTokenRefresh() is called) when:

  • The app deletes Instance ID
  • The app is restored on a new device
  • The user uninstalls/reinstall the app
  • The user clears app data.
activesince93
  • 1,651
  • 15
  • 36
6

At the same time don not forget to include this in your manifest file to receive token id

<service
    android:name=".MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>
Kharak
  • 392
  • 5
  • 18
6

UPDATE 11-12-2020

When you use 'com.google.firebase:firebase-messaging:21.0.0' is FirebaseInstanceIdis depreacted now

Now we need to use FirebaseInstallations.getInstance().getToken() and FirebaseMessaging.getInstance().token

SAMPLE CODE

FirebaseInstallations.getInstance().getToken(true).addOnCompleteListener {
            firebaseToken = it.result!!.token
        }

// OR

FirebaseMessaging.getInstance().token.addOnCompleteListener {
            if(it.isComplete){
                firebaseToken = it.result.toString()
                Util.printLog(firebaseToken)
            }
        }
AskNilesh
  • 58,437
  • 15
  • 99
  • 129
  • I'm using `FirebaseMessaging.getInstance().token` only to refresh Token manually together with `implementation platform('com.google.firebase:firebase-bom:26.2.0')` – murt Dec 21 '20 at 13:55
4

In firebase-messaging:17.1.0 and newer the FirebaseInstanceIdService is deprecated, you can get the onNewToken on the FirebaseMessagingService class as explained on https://stackoverflow.com/a/51475096/1351469

But if you want to just get the token any time, then now you can do it like this:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( this.getActivity(),  new OnSuccessListener<InstanceIdResult>() {
  @Override
  public void onSuccess(InstanceIdResult instanceIdResult) {
    String newToken = instanceIdResult.getToken();
    Log.e("newToken",newToken);
  }
});
jcesarmobile
  • 45,750
  • 8
  • 107
  • 152
  • Can this be returned, so the same function can be used at many places or we have to copy and paste because of the asynchronous nature of firebase – DragonFire Aug 21 '19 at 02:22
4

The FirebaseInstanceId.getInstance().getInstanceId() is deprecated. Based on firebase document, you can retrieve the current registration token using following code:

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
          if (!task.isSuccessful()) {
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          }

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    });
khesam109
  • 181
  • 1
  • 8
3

If are using some auth function of firebase, you can take token using this:

//------GET USER TOKEN-------
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getToken(true)
        .addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
            public void onComplete(@NonNull Task<GetTokenResult> task) {
                if (task.isSuccessful()) {
                    String idToken = task.getResult().getToken();
                      // ...
                }
            }
        });

Work well if user are logged. getCurrentUser()

Diego Venâncio
  • 4,095
  • 2
  • 31
  • 56
3

You can use this method to get device token with firebase

 FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
            String deviceToken = task.getResult();
        }
    });
Stefano Mtangoo
  • 4,986
  • 4
  • 35
  • 83
Najaf Ali
  • 1,187
  • 12
  • 23
  • the outcomes are different in both the ways. Can you please explain a bit about this? – Vivek Rathaur Feb 04 '21 at 11:48
  • the first one gives a lengthy token generated by firebase manipulations and original key token in plus and it generates the token on application id base a custom token you can say , but the second one is the genuine device token . and the last one is short in length just the difference is custom and without custom , – Najaf Ali Feb 08 '21 at 05:58
  • That first one is not the answer to this question and well misleading. The second one is the answer – Stefano Mtangoo Mar 03 '21 at 13:13
  • yes @StefanoMtangoo you are saying true and that's why i wrote in above the second one is okay but the firebase give these two methods but i recommend the second one, am going to remove the first one – Najaf Ali Mar 26 '21 at 12:47
  • Remove it as it is causing unnecessary pain and does not answer the question asked. Remaining with one and correct answer should be enough IMHO – Stefano Mtangoo Mar 29 '21 at 05:46
  • @StefanoMtangoo yes i removed that now thanks for assisting me to make it better – Najaf Ali Mar 31 '21 at 09:38
2

try this

FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener(OnSuccessListener<InstanceIdResult> { instanceIdResult ->
             fcm_token = instanceIdResult.token}
Mohammad Rbabah
  • 452
  • 2
  • 10
2

This the latest code to get fcm token in Activity (2021).

FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(new OnCompleteListener<String>() {
                    @Override
                    public void onComplete(@NonNull Task<String> task) {
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
                            return;
                        }
                        // Get new FCM registration token
                        String token = task.getResult();

                        Log.d(TAG, "fcm token : "+token);
                        
                    }
                });

For new Token just add the newToken Method in FirebaseMessagingService extended class.

@Override
    public void onNewToken(String token) {
        super.onNewToken(token);
        Log.d(TAG, token);
    }
Shrawan
  • 649
  • 5
  • 6
1

for those who land here, up to now FirebaseInstanceIdService is deprecated now, use instead:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onNewToken(String token) {
        Log.d("MY_TOKEN", "Refreshed token: " + token);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        // sendRegistrationToServer(token);
    }
}

and declare in AndroidManifest

<application... >

<service android:name=".fcm.MyFirebaseMessagingService">
    <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
</application>
user1908375
  • 937
  • 1
  • 12
  • 32
1
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
            @Override
            public void onComplete(@NonNull Task<InstanceIdResult> task) {
                if (!task.isSuccessful()) {
                    Log.w(TAG, "getInstanceId failed", task.getException());
                    return;
                }

                // Get new Instance ID token
                String **token** = task.getResult().getToken();

            }
        });
pruthwiraj.kadam
  • 729
  • 7
  • 10
1

Example to get firebase token inside suspend function

override suspend fun sendTokenToServer() {
    try {
 
        val token = FirebaseMessaging.getInstance().token.await()
        Log.i("TAG", "token " + token)
    } catch (exception:Exception) {

    }
}
Linh
  • 43,513
  • 18
  • 206
  • 227
0

FirebaseInstanceId.getInstance().getInstanceId() deprecated. Now get user FCM token

 FirebaseMessaging.getInstance().getToken()
            .addOnCompleteListener(new OnCompleteListener<String>() {
                @Override
                public void onComplete(@NonNull Task<String> task) {
                    if (!task.isSuccessful()) {
                        System.out.println("--------------------------");
                        System.out.println(" " + task.getException());
                        System.out.println("--------------------------");
                        return;
                    }

                    // Get new FCM registration token
                    String token = task.getResult();

                    // Log 
                    String msg = "GET TOKEN " + token;
                    System.out.println("--------------------------");
                    System.out.println(" " + msg);
                    System.out.println("--------------------------");

                }
            });
0

I'll make this short. This is the only non-deprecated way to retrieve the Firebase's token:

FirebaseInstallations.getInstance().getToken(true).addOnCompleteListener(task -> { 
   // get token 
   String token = task.getResult().getToken();      
})
Hung Vu
  • 11
  • 1
  • 2
-1

You can use the following in Firebase (FCM) to get the token:

FirebaseInstanceId.getInstance().getToken();
Grant Miller
  • 19,410
  • 15
  • 108
  • 135
Ahmed Sayed
  • 135
  • 1
  • 2
-11
Settings.Secure.getString(getContentResolver(),
                     Settings.Secure.ANDROID_ID);