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.
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
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
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()));
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:
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.
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!
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());
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
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) {
}
}
If you are using above 'com.google.firebase:firebase-messaging:22.0.0'
Get FCM Token (Force) with Kotlin way:
FirebaseMessaging.getInstance().token.addOnCompleteListener { task: Task<String> ->
if (!task.isSuccessful) {
return#addOnCompleteListener
}
pushToken = task.result
Log.i("PUSH_TOKEN", "pushToken: $pushToken")
}
And you can get token via onNewToken method. (This class must be implemented)
class PushNotificationService: FirebaseMessagingService() {
override fun onNewToken(token: String) {
Log.e("PUSH_TOKEN", "Refreshed firebase token: $token")
}
}
You need add PushNotificationService to AndroidManifest.xml
<service
android:name=".PushNotificationService"
android:exported="false"
tools:ignore="Instantiatable">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
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.
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>
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.
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();
}
});
If you are using kotlin and co-routine then add kotlin coroutine play
library
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:x.x.x'
use this simple method:
FirebaseMessaging.getInstance().token.await()
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)
}
}
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();
}
});
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);
}
});
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()
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);
}
try this
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener(OnSuccessListener<InstanceIdResult> { instanceIdResult ->
fcm_token = instanceIdResult.token}
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>
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();
}
});
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) {
}
}
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();
})
Use below code for latest firebase version - 'com.google.firebase:firebase-messaging:22.0.0'
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
//handle token error
return;
}
strAppToken = task.getResult();
});
You can use the following in Firebase (FCM) to get the token:
FirebaseInstanceId.getInstance().getToken();
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("--------------------------");
}
});
Flutter solution:
var token = await FirebaseMessaging.instance.getToken();
Settings.Secure.getString(getContentResolver(),
Settings.Secure.ANDROID_ID);
Related
We have been through various Stackoverflow questions and answers, and looked through documentation and articles but all the approaches we've tried such as FireBaseInstanceId and extending the FirebaseMessagingService all result in an empty token.
It is not clear how we get the token for the user's device, for push notification purposes.
Could someone please clarify how in 2021 we can get the user's device token?
Thanks
FireBaseInstanceId was deprecated and documentation say to use FirebaseMessaging for retrieve FCM token.
In particular the method getToken() works in this way:
Returns the FCM registration token for this Firebase project. This creates a Firebase Installations ID, if one does not exist
So, in order to generate token, I don't think is mandatory to extends FirebaseMessagingService, just call it like so wherever you want
FirebaseMessaging.getInstance().token.addOnCompleteListener {
if (!it.isSuccessful) {
return#addOnCompleteListener
}
val token = it.result //this is the token retrieved
}
Once you have a sample push notification project working, then the Java code is:
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();
}
});
Source= https://firebase.google.com/docs/cloud-messaging/android/client
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onNewToken(String token) {
super.onNewToken(token);
Log.e("newToken", token);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
Add this in Android manifest file:
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Whenever your Application is installed first time and open, MyFirebaseMessagingService created and onNewToken(String token) method called and token generated which is your Device Token or FCM Token.
from this way you can get the unique device id
TelephonyManager telephonyManager;
telephonyManager = (TelephonyManager) getSystemService(Context.
TELEPHONY_SERVICE);
getDeviceId() will returns the unique device ID.
String deviceId = telephonyManager.getDeviceId();
By the way this needs permission of android.permission.READ_PHONE_STATE
I'm using firebase notifications. There are some times when I don't get the pushtoken on time. How can I wait for it?
pushToken = firebaseIDService.getToken();
//SOME CODE
registerUser(pushToken);
So, I just want to stop that function until I get the result of the getToken().
Thanks.
The token is generated asynchronously, and may be refreshed periodically. To ensure your app uses the latest token, implement FirebaseInstanceIdService .onTokenRefresh as shown in the documentation on monitoring token generation:
The onTokenRefreshcallback fires whenever a new token is generated, so calling getToken in its context ensures that you are accessing a current, available registration token. Make sure you have added the service to your manifest, then call getToken in the context of onTokenRefresh, and log the value as shown:
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// 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(refreshedToken);
}
The sendRegistrationToServer function in the above snippet is something you'd implement yourself, so likely equivalent to registerUser in your code
Warning! Don't use it on main thread!
Also, it's a bad practice (probably), better use answer by #FrankvanPuffelen.
And I'm not sure it's working, but I'm using same approach for few async operations.
#WorkerThread
public String getTokeSync(Context context) {
String token = FirebaseInstanceId.getInstance().getToken();
if (token != null)
return token;
IntentFilter filter = new IntentFilter();
filter.addAction("com.google.android.c2dm.intent.RECEIVE");
filter.addCategory(BuildConfig.APPLICATION_ID);
final CountDownLatch lock = new CountDownLatch(1);
final FirebaseInstanceIdReceiver br = new FirebaseInstanceIdReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
token = FirebaseInstanceId.getInstance().getToken();
lock.countDown();
context.unregisterReceiver(this);
}
}
context.registerReceiver(br, filter);
lock.await(); // Better use await with timeout
return token;
}
I'm implementing Firebase Cloud Messaging and It's driving me crazy with a lot of trouble. I want to update the token everytime the user logs in, so when the users logs in I made a Service which delete the token and creates a new one. So the method onrefreshToken is called. And now what I want is to save the user, the idDevice and the token on database, but I don't know how to do it, because this service(MyFirebaseInstanceIdService) is never created, so I haven't put an extra.
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("myFireBase", "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String refreshedToken) {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String idDevice = telephonyManager.getDeviceId();
// Token token = new Token(refreshedToken, idDevice, usuario);
// Call server to save the token
}
}
FirebaseInstanceIdService will call only ones when app will instrall so save on sharedpreference on first time and get value from shared preference on login time.
use like this.
public class FirebaseService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
String Tocken_Refresh= FirebaseInstanceId.getInstance().getToken();
SharedPreferences sharedPreferences=getApplication().getSharedPreferences(MyPREFERENCESGCM, MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("fcm",Tocken_Refresh);
editor.commit();
}
}
Can you help me out here? My code was working like 3 days before. Now when I run, i cant get GCM token generated for my device. Here is my code:
private void registerGCM() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
String token = null;
try {
InstanceID instanceID = InstanceID.getInstance(this);
token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.e(TAG, "GCM Registration Token: " + token);
// sending the registration id to our server
sendRegistrationToServer(token);
sharedPreferences.edit().putBoolean(Config.SENT_TOKEN_TO_SERVER, true).apply();
} catch (Exception e) {
Log.e(TAG, "Failed to complete token refresh", e);
sharedPreferences.edit().putBoolean(Config.SENT_TOKEN_TO_SERVER, false).apply();
}
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(Config.REGISTRATION_COMPLETE);
registrationComplete.putExtra("token", token);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
To obtain a registration token, Google provides the Instance ID API to handle the creation and updating of registration tokens.
You must include the InstanceIDListenerService in your manifest file to use this.
<service android:name="[.MyInstanceIDService]" android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
Then to obtain a token, call instanceID.getToken, providing the app server's sender ID and setting the scope to GoogleCloudMessaging.INSTANCE_ID_SCOPE.
NOTE: Do not call this method in the main thread; instead, use a
service that extends
IntentService
Here is the sample code for this.
Public class RegistrationIntentService extends IntentService {
// ...
#Override
public void onHandleIntent(Intent intent) {
// ...
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// ...
}
// ...
}
For more information, just check this documentation and this complete sample code.
I am using FCM to provide notifications in my app. Everything worked well, but now I realised that, when I install my application using Android Studio (not from GooglePlay) the token is null at first run. When I close my app and restart it, the token is not null anymore. What cause this problem and how can I avoid it?
InstanceIDService:
public class InstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
registerToken(token);
}
private void registerToken(String token) {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("Token",token)
.build();
Request request = new Request.Builder()
.url("url_to_registration_script")
.post(body)
.build();
try {
client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In MainActivity:
FirebaseMessaging.getInstance().subscribeToTopic("topic");
String token = FirebaseInstanceId.getInstance().getToken();
Log.d("TOKEN", token);
Last log returns null when app is installed and started for the first time
Registration script:
<?php
if (isset($_POST["Token"])) {
$_uv_Token=$_POST["Token"];
$conn = mysqli_connect("localhost","user","pass","db") or die("Error connecting");
$q="INSERT INTO users (Token) VALUES ( '$_uv_Token') "
." ON DUPLICATE KEY UPDATE Token = '$_uv_Token';";
mysqli_query($conn,$q) or die(mysqli_error($conn));
mysqli_close($conn);
}
?>
The token is fetched asynchronously on first app start. You have to wait for onTokenRefresh() to be called in your FirebaseInstanceIdService before the token can be accessed.
uninstall the app from emulator and run again , so that the onTokenRefreshed method will be called again .
To check wether you are already registered and you just want to know the FCM TOken
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
add the above line in MyFirebaseMessagingService class any where(in oncreate method ) and just Toast or log the refreshedToken.
Just replace:
String token = instanceID.getToken();
with:
String token = instanceID.getToken($SENDER_ID, "FCM");
and it will work.
I was facing the same problem. I looked through a lot of SO posts and other forums and I found a solution that worked for me. FCM documentation says to use this method to get a token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
I found a post online (I apologize, I don't remember which one. I found it a while ago) that used this method instead:
String refreshedToken = FirebaseInstanceId.getInstance().getToken() (String authorizedEntity, String scope);
FCM documentation describes the first method as:
Return the master token for the default Firebase project.
While the second one is described as:
Returns a token that authorizes an Entity to perform an action on behalf of the application identified by Instance ID.
This is similar to an OAuth2 token except, it applies to the application instance instead of a user.
For example, to get a token that can be used to send messages to an application via FirebaseMessaging, set to the sender ID, and set to "FCM".
I have been looking into why the first method call takes a longer time to return a token, but I haven't found an answer yet. Hope this helps.
Even I had the same issue. I had given the Log statement to print token in onCreate of my launcher activity. It takes time to refresh the token once you uninstall the app. Thats why you get null. You have to wait for a bit to get the token refreshed.
Sometimes network issues may occur, even internet is working fine....
check your FirebaseInstancId class defined in Manifest file in your android project.
I just fell in same issue and this is the way I fixed it. Call the block somewhere in onCreate() method of your activity. I want to sent the Token to my Parse server so you must change it based on your needs.
This is the sample I followed.
private void subscribeUserToParse() {
String deviceToken = FirebaseInstanceId.getInstance().getToken();
if (TextUtils.isEmpty(deviceToken)) {
Intent intent = new Intent(this, MyFirebaseInstanceIDService.class);
startService(intent);
return;
}
User user = UserUtil.retrieveUserFromDB(mRealm);
String objectId = user.getParseObjectId();
if (!TextUtils.isEmpty(objectId)) {
ParseUtils.subscribeWithUsersObjectId(objectId, deviceToken);
}
}
The biggest issue i faced after writing the correct code is:-
not the latest version of google play services in build-gradle,
So always use the google-play-services version shown by firebase in setting up dialog
I was having the same problem in a Android 4.2 device.
So, to solve the problem, first, check if your service, in the manifest, if it have a priority like this:
<service
android:name=".other.MyFirebaseInstanceIDService"
android:exported="false">
<intent-filter android:priority="1000">
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
Second, use a broadcast intent to notify your MainActivity that changed the token:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
final Intent intent = new Intent("tokenReceiver");
final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
intent.putExtra("token",refreshedToken);
broadcastManager.sendBroadcast(intent);
}
Then in MainActivity, in the onCreate, add this:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
LocalBroadcastManager.getInstance(this).registerReceiver(tokenReceiver,
new IntentFilter("tokenReceiver"));
}
and, in the MainActivity, add a new BroadcastReceiver:
BroadcastReceiver tokenReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String token = intent.getStringExtra("token");
if(token != null)
{
Log.e("firebase", String.valueOf(token));
// send token to your server
}
}
};
Since the getToken() method is deprecated, you have to replace it with a listener.
Just replace String token = FirebaseInstanceId.getInstance().getToken(); by the following code snippet:
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();
// 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();
}
});
You can find the official google documentation here: https://firebase.google.com/docs/cloud-messaging/android/client
And a nice medium post will help you out as well: https://medium.com/#cdmunoz/fcm-getinstance-gettoken-in-android-is-now-deprecated-how-to-fix-it-3922a94f4fa4