tutorial setup notificaciones google gcm android firebase firebase-cloud-messaging

android - setup - Firebase Cloud Messaging-Manejo del cierre de sesión



xamarin forms & firebase cloud messaging ios setup (6)

Los desarrolladores nunca deben anular el registro de la aplicación cliente como mecanismo para cerrar sesión o para cambiar entre usuarios, por las siguientes razones:

  • Un token de registro no está asociado con un usuario conectado en particular. Si la aplicación cliente se da de baja y luego se vuelve a registrar, la aplicación puede recibir el mismo token de registro o un token de registro diferente.
  • La anulación del registro y la reinscripción pueden demorar hasta cinco minutos en propagarse. Durante este tiempo, los mensajes pueden ser rechazados debido al estado no registrado, y los mensajes pueden ir al usuario equivocado. Para asegurarse de que los mensajes van al usuario deseado:

  • El servidor de aplicaciones puede mantener una asignación entre el usuario actual y el token de registro.

  • La aplicación cliente puede verificar para asegurarse de que los mensajes que recibe coinciden con el usuario conectado.

esto fue de una documentación obsoleta de google: https://developers.google.com/cloud-messaging/registration#unregistration-and-unsubscription

pero hay razones para creer que esto todavía está disponible

compruebe este código de Firebase https://github.com/firebase/functions-samples/blob/master/fcm-notifications/functions/index.js

y este https://github.com/firebase/friendlychat-web/blob/master/cloud-functions/public/scripts/main.js

¿Cómo manejo la situación, cuando el usuario cierra sesión en mi aplicación y ya no quiero que reciba notificaciones en el dispositivo?

Lo intenté

FirebaseInstanceId.getInstance().deleteToken(FirebaseInstanceId.getInstance().getId(), FirebaseMessaging.INSTANCE_ID_SCOPE)

Pero aún recibo las notificaciones del registration_id mi dispositivo.

También me aseguré de que este es el token que debería eliminar:

FirebaseInstanceId.getInstance().getToken(FirebaseInstanceId.getInstance().getId(), FirebaseMessaging.INSTANCE_ID_SCOPE)

o simplemente FirebaseInstanceId.getInstance().getToken() ).

También probé FirebaseInstanceId.getInstance().deleteInstanceId() , pero la próxima vez que llame a FirebaseInstanceId.getInstance.getToken recibo nulo (funciona en el segundo intento).

Supongo que después de deleteInstanceId podría llamar inmediatamente a getToken() nuevamente, pero parece un hack. Y también está esta respuesta que establece que no se debe hacer, pero propone eliminar el token que aparentemente no funciona.

Entonces, ¿cuál es el método correcto para manejar esto?


Bueno. Así que logré hacer algunas pruebas y concluí lo siguiente:

  1. deleteToken() es la contraparte de getToken(String, String) , pero no para getToken() .

Solo funciona si la ID del remitente que está pasando es una ID del remitente diferente (no la misma ID que se puede ver en su google-services.json). Por ejemplo, si desea permitir que un Servidor diferente envíe a su aplicación, llame a getToken("THEIR_SENDER_ID", "FCM") para darles autorización para enviar a su aplicación. Esto devolverá un token de registro diferente que corresponde solo a ese remitente específico.

En el futuro, si elige eliminar su autorización para enviar a su aplicación, deberá utilizar deleteToken("THEIR_SENDER_ID", "FCM") . Esto invalidará el token correspondiente, y cuando el remitente intente enviar un mensaje, como el comportamiento previsto, recibirá un error NotRegistered .

  1. Para eliminar el token de su propio remitente, el manejo correcto es usar deleteInstanceId() .

Mencionando especialmente esta respuesta de @Prince , específicamente el ejemplo de código para ayudarme con esto.

Como @ MichałK ya está haciendo en su publicación, después de llamar a deleteInstanceId() , se debe llamar a getToken() para enviar una solicitud de un nuevo token. Sin embargo, no tiene que llamarlo la segunda vez. Siempre que se onTokenRefresh() onNewToken() , se activará automáticamente para proporcionarle el nuevo token.

Para abreviar, deleteInstanceId() > getToken() > check onTokenRefresh() onNewToken() .

Nota : Llamar a deleteInstanceId() no solo eliminará el token para su propia aplicación. Eliminará todas las suscripciones de temas y todos los demás tokens asociados con la instancia de la aplicación.

¿Estás seguro de que estás llamando a deleteToken() correctamente? El valor para la audiencia debe ser (también visto por mi respuesta que ha vinculado) está "configurado en la ID del remitente del servidor de aplicaciones". Está pasando el valor getId() que no es el mismo que el Id. Del remitente (contiene el valor de id de la instancia de la aplicación). Además, ¿cómo envía el mensaje (Servidor de aplicaciones o Consola de notificaciones)?

getToken() y getToken(String, String) devuelve diferentes tokens. Mira mi respuesta here .

También probé FirebaseInstanceId.getInstance().deleteInstanceId() , pero la próxima vez que llame a FirebaseInstanceId.getInstance.getToken recibo nulo (funciona en el segundo intento).

Probablemente sea porque la primera vez que llamas a getToken() , todavía se está generando. Es solo el comportamiento previsto.

Supongo que después de deleteInstanceId podría llamar inmediatamente a getToken() nuevamente, pero parece un hack.

Realmente no. Es cómo obtendrá el nuevo token generado (siempre que ya esté generado). Entonces creo que está bien.


Como getToken() está en desuso , use getInstanceId() para regenerar un nuevo token. Tiene el mismo efecto.

@WorkerThread public void deleteInstanceId() throws IOException { if (Looper.getMainLooper() == Looper.myLooper()) { throw new IOException("MAIN_THREAD"); } else { String var1 = zzh(); this.zza(this.zzal.deleteInstanceId(var1)); this.zzl(); } }


Estaba trabajando en el mismo problema, cuando había terminado mi logout() desde mi aplicación. Pero el problema era que después de cerrar sesión, todavía recibía notificaciones push de Firebase. Traté de eliminar el token Firebase . Pero después de eliminar el token en mi método logout() , es null cuando lo consulto en mi método login() . Después de trabajar 2 días finalmente obtuve una solución.

  1. En su método logout() , elimine el token Firebase en segundo plano porque no puede eliminar el token Firebase del hilo principal

    new AsyncTask<Void,Void,Void>() { @Override protected Void doInBackground(Void... params) { try { FirebaseInstanceId.getInstance().deleteInstanceId(); } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { // Call your Activity where you want to land after log out } }.execute();

  2. En su método login() , genere el token Firebase nuevamente.

    new AsyncTask<Void,Void,Void>() { @Override protected Void doInBackground(Void... params) { String token = FirebaseInstanceId.getInstance().getToken(); // Used to get firebase token until its null so it will save you from null pointer exeption while(token == null) { token = FirebaseInstanceId.getInstance().getToken(); } return null; } @Override protected void onPostExecute(Void result) { } }.execute();


Hice una breve investigación sobre cuál sería la solución más elegante para recuperar el control total (suscribirse y cancelar la suscripción a FCM) como antes. Habilite y deshabilite el FCM después de que el usuario haya iniciado sesión o se haya desconectado.

Paso 1. - Prevenir la inicialización automática

Firebase ahora maneja el InstanceID y todo lo demás que necesita generar un token de registro. En primer lugar, debe evitar la inicialización automática . Según la documentación de configuración oficial , debe agregar estos valores de metadatos a su AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?> <application> <!-- FCM: Disable auto-init --> <meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" /> <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" /> <!-- FCM: Receive token and messages --> <service android:name=".FCMService"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/> </intent-filter> </service> </application>

Ahora deshabilitó el proceso de solicitud de token automático. Al mismo tiempo, tiene una opción para habilitarlo nuevamente en tiempo de ejecución por código.

Paso 2. - Implemente las enableFCM() y disableFCM()

Si habilita la inicialización automática nuevamente, recibirá un nuevo token de inmediato, por lo que esta es una manera perfecta de implementar el método enableFCM() . Toda la información de suscripción asignada a InstanceID, por lo tanto, cuando la elimine, inicie para cancelar la suscripción de todo el tema. De esta manera puede implementar el método disableFCM() , simplemente desactive el inicio automático antes de eliminarlo.

public class FCMHandler { public void enableFCM(){ // Enable FCM via enable Auto-init service which generate new token and receive in FCMService FirebaseMessaging.getInstance().setAutoInitEnabled(true); } public void disableFCM(){ // Disable auto init FirebaseMessaging.getInstance().setAutoInitEnabled(false); new Thread(() -> { try { // Remove InstanceID initiate to unsubscribe all topic // TODO: May be a better way to use FirebaseMessaging.getInstance().unsubscribeFromTopic() FirebaseInstanceId.getInstance().deleteInstanceId(); } catch (IOException e) { e.printStackTrace(); } }).start(); } }

Paso 3. - Implementación de FCMService - FCMService tokens y mensajes

En el último paso, debe recibir el nuevo token y enviarlo directamente a su servidor. Por otro lado, recibirá su mensaje de datos y simplemente haga lo que quiera.

public class FCMService extends FirebaseMessagingService { @Override public void onNewToken(String token) { super.onNewToken(token); // TODO: send your new token to the server } @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); String from = remoteMessage.getFrom(); Map data = remoteMessage.getData(); if (data != null) { // TODO: handle your message and data sendMessageNotification(message, messageId); } } private void sendMessageNotification(String msg, long messageId) { // TODO: show notification using NotificationCompat } }

Creo que esta solución es clara, simple y transparente. Lo probé en un entorno de producción y funciona. Espero que haya sido de ayuda.


Sé que llego tarde a la fiesta. deleteInstanceId() debe llamar a deleteInstanceId() desde el hilo de fondo ya que es una llamada de bloqueo. Simplemente verifique el método deleteInstanceId() en la clase FirebaseInstanceId() .

public static void resetInstanceId() { new Thread(new Runnable() { @Override public void run() { try { FirebaseInstanceId.getInstance().deleteInstanceId(); FirebaseInstanceId.getInstance().getInstanceId(); Helper.log(TAG, "InstanceId removed and regenerated."); } catch (IOException e) { e.printStackTrace(); } } }).start(); }

Puede iniciar un IntentService para eliminar la identificación de la instancia y los datos asociados con ella.