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:
-
deleteToken()
es la contraparte degetToken(String, String)
, pero no paragetToken()
.
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
.
-
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 aFirebaseInstanceId.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 agetToken()
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.
-
En su método
logout()
, elimine el token Firebase en segundo plano porque no puede eliminar el token Firebase del hilo principalnew 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();
-
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.