89 votes

Firebase Cloud Messaging - Gestion de la déconnexion

Comment gérer la situation lorsque l'utilisateur se déconnecte de mon application et que je ne veux plus qu'il reçoive de notifications sur l'appareil.

J'ai essayé

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

Mais je reçois toujours les notifications sur mon appareil. registration_id .

Je me suis également assuré que c'est le jeton que je dois supprimer :

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

ou simplement FirebaseInstanceId.getInstance().getToken() ).

J'ai aussi essayé FirebaseInstanceId.getInstance().deleteInstanceId() mais la fois suivante, j'appelle FirebaseInstanceId.getInstance.getToken Je reçois null (cela fonctionne au deuxième essai).

Je suppose, après deleteInstanceId Je pourrais immédiatement appeler getToken() encore, mais ça ressemble à un piratage. Et il y a aussi cette réponse qui indique que cela ne devrait pas être fait, mais il propose de supprimer le jeton, ce qui apparemment ne fonctionne pas.

Quelle est donc la bonne méthode pour gérer cette situation ?

78voto

AL. Points 21726

Bon. J'ai donc réussi à faire quelques tests et j'en suis arrivé à la conclusion suivante :

  1. deleteToken() est la contrepartie de getToken(String, String) mais pas pour getToken() .

Cela ne fonctionne que si l'ID d'expéditeur que vous transmettez est un ID d'expéditeur différent (pas le même ID que celui que l'on peut voir dans votre google-services.json). Par exemple, si vous voulez autoriser un serveur différent à envoyer des messages à votre application, vous appelez getToken("THEIR_SENDER_ID", "FCM") pour leur donner autorisation à envoyer à votre application. Cela renverra un jeton d'enregistrement différent qui correspondra uniquement à cet expéditeur spécifique.

À l'avenir, si vous choisissez de supprimer leur autorisation à envoyer à votre application, vous devrez alors faire usage de deleteToken("THEIR_SENDER_ID", "FCM") . Cela invalidera le jeton correspondant et, lorsque l'expéditeur tentera d'envoyer un message, comme prévu, il recevra un message de type NotRegistered erreur.

  1. Pour supprimer le jeton de votre propre expéditeur, il faut utiliser la méthode suivante deleteInstanceId() .

Mention spéciale pour cette réponse de @Prince et plus particulièrement l'exemple de code pour m'aider à résoudre ce problème.

Comme @MichałK l'a déjà fait dans son post, après avoir appelé les deleteInstanceId() , getToken() doit être appelé afin d'envoyer une demande pour un nouveau jeton. Cependant, il n'est pas nécessaire de l'appeler une deuxième fois. Tant que onTokenRefresh() onNewToken() est implémenté, il devrait se déclencher automatiquement en vous fournissant le nouveau jeton.

Pour faire court, deleteInstanceId() > getToken() > vérifier onTokenRefresh() onNewToken() .

Note : Appel à deleteInstanceId() ne supprimera pas seulement le jeton pour votre propre application. Il supprimera tous les abonnements aux sujets et tous les autres jetons associés à l'instance de l'application.


Êtes-vous sûr que vous appelez deleteToken() correctement ? La valeur de l'audience devrait être (comme on peut le voir dans ma réponse que vous avez citée) "définie par l'ID de l'expéditeur du serveur d'applications". Vous passez la valeur getId() qui n'est pas le même que l'ID de l'expéditeur (il contient la valeur de l'ID de l'instance de l'application). De plus, comment envoyez-vous le message (App Server ou Console de Notifications) ?

getToken() y getToken(String, String) renvoie des jetons différents. Voir ma réponse aquí .

J'ai aussi essayé FirebaseInstanceId.getInstance().deleteInstanceId() mais la fois suivante, j'appelle FirebaseInstanceId.getInstance.getToken Je reçois null (cela fonctionne au deuxième essai).

C'est probablement parce que la première fois que vous appelez la fonction getToken() il est toujours généré. C'est juste le comportement prévu.

Je suppose, après deleteInstanceId Je pourrais immédiatement appeler getToken() encore, mais ça ressemble à un piratage.

Pas vraiment. C'est ainsi que vous obtiendrez le nouveau jeton généré (à condition qu'il soit déjà généré). Donc je pense que c'est bon.

35voto

J'ai fait une brève recherche sur ce qui serait la solution la plus élégante pour retrouver le contrôle total (abonnement et désabonnement au FCM) comme avant. Activer et désactiver le FCM après que l'utilisateur se soit connecté ou déconnecté.

Étape 1. - Empêcher l'initialisation automatique

Firebase gère désormais les InstanceID et tout ce qui est nécessaire pour générer un jeton d'enregistrement. Tout d'abord, vous devez empêcher initialisation automatique . Sur la base de la documentation officielle de mise en place vous devez ajouter ces méta-données à votre 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>

Vous avez maintenant désactivé le processus de demande automatique de jeton. En même temps, vous avez la possibilité de l'activer à nouveau au moment de l'exécution par code.

Étape 2. - Mettez en œuvre enableFCM() y disableFCM() fonctions

Si vous réactivez l'initialisation automatique, vous recevrez immédiatement un nouveau jeton, ce qui constitue un moyen parfait d'implémenter la méthode d'authentification des jetons. enableFCM() méthode. Toutes les informations d'abonnement sont assignées à l'InstanceID, de sorte que lorsque vous la supprimez, cela entraîne la désinscription de tous les sujets. De cette façon, vous pouvez implémenter disableFCM() méthode, il suffit de désactiver l'auto-init avant de le supprimer.

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();
    }

}

Étape 3. - FCMService mise en œuvre - réception de jetons et de messages

Dans la dernière étape, vous devez recevoir le nouveau jeton et l'envoyer directement à votre serveur. De l'autre côté, vous recevrez votre message de données et ferez ce que vous voulez.

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
    }
}

Je pense que cette solution est claire, simple et transparente. Je l'ai testée dans un environnement de production et elle fonctionne. J'espère que cela a été utile.

20voto

Sunil Points 1487

Je travaillais sur le même problème, quand j'avais fait mon logout() de mon application. Mais le problème était qu'après m'être déconnecté, je recevais toujours des notifications push de Firebase. J'ai essayé de supprimer le jeton Firebase . Mais après avoir supprimé le jeton dans mon fichier logout() méthode, il est null quand je le recherche dans mon login() méthode. Après avoir travaillé 2 jours, j'ai enfin trouvé une solution.

  1. Dans votre logout() supprimez le jeton Firebase en arrière-plan, car vous ne pouvez pas supprimer le jeton Firebase depuis le fil 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. Dans votre login() génère à nouveau le jeton Firebase.

    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();

10voto

Dan Alboteanu Points 1570

Les développeurs ne devraient jamais désenregistrer l'application cliente comme mécanisme de de déconnexion ou de changement d'utilisateur, pour les raisons suivantes :

  • Un jeton d'enregistrement n'est pas associé à un utilisateur connecté particulier. Si l'application cliente se désinscrit puis se réinscrit, l'application peut recevoir le même jeton d'enregistrement ou un jeton d'enregistrement différent.

  • Le désenregistrement et le réenregistrement peuvent prendre jusqu'à cinq minutes chacun pour se propager. Pendant ce temps, les messages peuvent être rejetés en raison de l'état de non enregistrement. l'état de non-enregistrement, et les messages peuvent être envoyés au mauvais utilisateur. Pour s'assurer que les messages parviennent à l'utilisateur visé :

  • Le serveur d'applications peut maintenir une correspondance entre l'utilisateur actuel et le jeton d'enregistrement.

  • L'application cliente peut alors vérifier que les messages qu'elle reçoit correspondent à l'utilisateur connecté.

docs

1voto

Sarweshkumar C R Points 350

Je sais que je suis en retard pour la fête. deleteInstanceId() doit être appelé depuis le fil d'arrière-plan puisqu'il s'agit d'un appel bloquant. Il suffit de vérifier la méthode deleteInstanceId() en [FirebaseInstanceId()](https://firebase.google.com/docs/reference/android/com/google/firebase/iid/FirebaseInstanceId.html#deleteInstanceId()) classe.

@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();
    }
}  

Vous pouvez lancer un IntentService pour supprimer l'id d'instance et les données qui lui sont associées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X