android - gettoken - Firebase FCM fuerza onTokenRefresh() para ser llamado
google cloud messaging to firebase (8)
FirebaseInstanceIdService
Esta clase está en desuso. A favor de anular onNewToken en FirebaseMessagingService. Una vez que se ha implementado, este servicio se puede eliminar de forma segura.
La nueva forma de hacer esto sería anular el método
onNewToken
de
FirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
Además, no olvide agregar el servicio en el Manifiesto.xml
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Estoy migrando mi aplicación de GCM a FCM.
Cuando un nuevo usuario instala mi aplicación, se
onTokenRefresh()
automáticamente a
onTokenRefresh()
.
El problema es que el usuario aún no ha iniciado sesión (sin ID de usuario).
¿Cómo puedo activar
onTokenRefresh()
después de que el usuario haya iniciado sesión?
Chicos tiene una solución muy simple
https://developers.google.com/instance-id/guides/android-implementation#generate_a_token
Nota: Si su aplicación usó tokens que fueron eliminados por deleteInstanceID, su aplicación necesitará generar tokens de reemplazo.
En lugar de eliminar el Id de instancia, elimine solo el token:
String authorizedEntity = PROJECT_ID;
String scope = "GCM";
InstanceID.getInstance(context).deleteToken(authorizedEntity,scope);
Esta respuesta no destruye la identificación de la instancia, sino que puede obtener la actual. También almacena uno actualizado en las preferencias compartidas.
Strings.xml
<string name="pref_firebase_instance_id_key">pref_firebase_instance_id</string>
<string name="pref_firebase_instance_id_default_key">default</string>
Utility.java (cualquier clase donde desee establecer / obtener preferencias)
public static void setFirebaseInstanceId(Context context, String InstanceId) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor;
editor = sharedPreferences.edit();
editor.putString(context.getString(R.string.pref_firebase_instance_id_key),InstanceId);
editor.apply();
}
public static String getFirebaseInstanceId(Context context) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String key = context.getString(R.string.pref_firebase_instance_id_key);
String default_value = context.getString(R.string.pref_firebase_instance_id_default_key);
return sharedPreferences.getString(key, default_value);
}
MyFirebaseInstanceIdService.java (extiende FirebaseInstanceIdService)
@Override
public void onCreate()
{
String CurrentToken = FirebaseInstanceId.getInstance().getToken();
//Log.d(this.getClass().getSimpleName(),"Inside Instance on onCreate");
String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);
if(CurrentToken != null && !savedToken.equalsIgnoreCase(defaultToken))
//currentToken is null when app is first installed and token is not available
//also skip if token is already saved in preferences...
{
Utility.setFirebaseInstanceId(getApplicationContext(),CurrentToken);
}
super.onCreate();
}
@Override
public void onTokenRefresh() {
.... prev code
Utility.setFirebaseInstanceId(getApplicationContext(),refreshedToken);
....
}
Android 2.0 y superior
onCreate
of service no se invoca cuando se inicia automáticamente (
source
).
En cambio,
onStartCommand
se reemplaza y se usa.
Pero en FirebaseInstanceIdService real se declara como final y no se puede anular.
Sin embargo, cuando comenzamos el servicio usando startService (), si el servicio ya se está ejecutando,
se usa
su
instancia original
(lo cual es bueno).
¡Nuestro onCreate () (definido anteriormente) también fue invocado !.
Use esto al comienzo de MainActivity o en cualquier punto que crea que necesita una identificación de instancia.
MyFirebaseInstanceIdService myFirebaseInstanceIdService = new MyFirebaseInstanceIdService();
Intent intent= new Intent(getApplicationContext(),myFirebaseInstanceIdService.getClass());
//Log.d(this.getClass().getSimpleName(),"Starting MyFirebaseInstanceIdService");
startService(intent); //invoke onCreate
Y finalmente,
Utility.getFirebaseInstanceId(getApplicationContext())
Tenga en cuenta que puede mejorar esto intentando mover el código startservice () al método getFirebaseInstanceId.
Esto está en RxJava2 en el escenario cuando un usuario cierra la sesión de su aplicación y otros usuarios inician sesión (misma aplicación) Para volver a generar y llamar al inicio de sesión (si el dispositivo del usuario no tenía conexión a Internet antes del inicio de la actividad y necesitamos enviar el token API de inicio de sesión)
Single.fromCallable(() -> FirebaseInstanceId.getInstance().getToken())
.flatMap( token -> Retrofit.login(userName,password,token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(simple -> {
if(simple.isSuccess){
loginedSuccessfully();
}
}, throwable -> Utils.longToast(context, throwable.getLocalizedMessage()));
Iniciar sesión
@FormUrlEncoded
@POST(Site.LOGIN)
Single<ResponseSimple> login(@Field("username") String username,
@Field("password") String pass,
@Field("token") String token
);
Intenta implementar
FirebaseInstanceIdService
para obtener un token de actualización.
Acceda al token de registro:
Puede acceder al valor del token extendiendo
FirebaseInstanceIdService
.
Asegúrese de haber agregado el servicio a su
manifest
, luego llame a
getToken
en el contexto de
onTokenRefresh
y registre el valor como se muestra:
@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);
}
Código completo:
import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
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);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* 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.
}
}
Mira mi respuesta here .
EDICIONES:
No debería iniciar un FirebaseInstanceIdService usted mismo.
Se llamará cuando el sistema determine que los tokens deben actualizarse. La aplicación debe llamar a getToken () y enviar los tokens a todos los servidores de aplicaciones.
Esto no se llamará con mucha frecuencia, es necesario para la rotación de teclas y para manejar los cambios de ID de instancia debido a:
- La aplicación elimina la ID de instancia
- La aplicación se restaura en un nuevo dispositivo Usuario
- desinstala / reinstala la aplicación
- El usuario borra los datos de la aplicación
El sistema acelerará el evento de actualización en todos los dispositivos para evitar sobrecargar los servidores de aplicaciones con actualizaciones de tokens.
Prueba a continuación :
llamaría a FirebaseInstanceID.getToken () en cualquier lugar fuera de su hilo principal (ya sea un servicio, AsyncTask, etc.), almacene el token devuelto localmente y envíelo a su servidor. Luego, cada vez que se
onTokenRefresh()
, volvería a llamar a FirebaseInstanceID.getToken () , obtendrá un nuevo token y lo enviará al servidor (probablemente también el antiguo token para que su servidor pueda eliminarlo, reemplazándolo con el uno nuevo).
Mantengo un indicador en pref compartido que indica si el token gcm se envió al servidor o no. En la pantalla de bienvenida cada vez que llamo a un método sendDevicetokenToServer. Este método verifica si la identificación del usuario no está vacía y el estado de envío de gcm envía el token al servidor.
public static void sendRegistrationToServer(final Context context) {
if(Common.getBooleanPerf(context,Constants.isTokenSentToServer,false) ||
Common.getStringPref(context,Constants.userId,"").isEmpty()){
return;
}
String token = FirebaseInstanceId.getInstance().getToken();
String userId = Common.getUserId(context);
if(!userId.isEmpty()) {
HashMap<String, Object> reqJson = new HashMap<>();
reqJson.put("deviceToken", token);
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<JsonElement> call = apiService.updateDeviceToken(reqJson,Common.getUserId(context),Common.getAccessToken(context));
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(Call<JsonElement> call, Response<JsonElement> serverResponse) {
try {
JsonElement jsonElement = serverResponse.body();
JSONObject response = new JSONObject(jsonElement.toString());
if(context == null ){
return;
}
if(response.getString(Constants.statusCode).equalsIgnoreCase(Constants.responseStatusSuccess)) {
Common.saveBooleanPref(context,Constants.isTokenSentToServer,true);
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void onFailure(Call<JsonElement> call, Throwable throwable) {
Log.d("", "RetroFit2.0 :getAppVersion: " + "eroorrrrrrrrrrrr");
Log.e("eroooooooorr", throwable.toString());
}
});
}
}
En la clase MyFirebaseInstanceIDService
@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.
Common.saveBooleanPref(this,Constants.isTokenSentToServer,false);
Common.sendRegistrationToServer(this);
FirebaseMessaging.getInstance().subscribeToTopic("bloodRequest");
}
Se
onTokenRefresh()
método
onTokenRefresh()
cada vez que se genere un nuevo token.
Tras la instalación de la aplicación, se generará de inmediato (como ha sido el caso).
También se llamará cuando el token haya cambiado.
De acuerdo con la guía
FirebaseCloudMessaging
:
Puede dirigir las notificaciones a un único dispositivo específico. En el inicio inicial de su aplicación, el SDK de FCM genera un token de registro para la instancia de la aplicación cliente.
Enlace de origen: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token
Esto significa que el registro del token es por aplicación.
Parece que le gustaría utilizar el token después de que un usuario haya iniciado sesión. Lo que sugeriría es que guarde el token en el método
onTokenRefresh()
en el almacenamiento interno o en las preferencias compartidas.
Luego, recupere el token del almacenamiento después de que un usuario inicie sesión y registre el token con su servidor según sea necesario.
Si desea forzar manualmente
onTokenRefresh()
, puede crear un IntentService y eliminar la instancia del token.
Luego, cuando llame a getToken, se
onTokenRefresh()
llamar al método
onTokenRefresh()
.
Código de ejemplo:
public class DeleteTokenService extends IntentService
{
public static final String TAG = DeleteTokenService.class.getSimpleName();
public DeleteTokenService()
{
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent)
{
try
{
// Check for current token
String originalToken = getTokenFromPrefs();
Log.d(TAG, "Token before deletion: " + originalToken);
// Resets Instance ID and revokes all tokens.
FirebaseInstanceId.getInstance().deleteInstanceId();
// Clear current saved token
saveTokenToPrefs("");
// Check for success of empty token
String tokenCheck = getTokenFromPrefs();
Log.d(TAG, "Token deleted. Proof: " + tokenCheck);
// Now manually call onTokenRefresh()
Log.d(TAG, "Getting new token");
FirebaseInstanceId.getInstance().getToken();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void saveTokenToPrefs(String _token)
{
// Access Shared Preferences
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
// Save to SharedPreferences
editor.putString("registration_id", _token);
editor.apply();
}
private String getTokenFromPrefs()
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
return preferences.getString("registration_id", null);
}
}
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
class MyFirebaseIIDService: FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
NotificationHub hub;
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "FCM token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Register with Notification Hubs
hub = new NotificationHub(Constants.NotificationHubName,
Constants.ListenConnectionString, this);
Employee employee = JsonConvert.DeserializeObject<Employee>(Settings.CurrentUser);
//if user is not logged in
if (employee != null)
{
var tags = new List<string>() { employee.Email};
var regID = hub.Register(token, tags.ToArray()).RegistrationId;
Log.Debug(TAG, $"Successful registration of ID {regID}");
}
else
{
FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance).DeleteInstanceId();
hub.Unregister();
}
}
}