web-dev-qa-db-fra.com

Messagerie Google Cloud - Parfois, les messages ne sont pas reçus tant que l'état du réseau n'est pas modifié

En travaillant sur un petit projet qui intègre GCM, je suis tombé sur un problème un peu étrange.

Parfois, lorsque je commence à regarder le journal pour voir si les messages sont reçus, les messages ne semblent pas arriver tant que je n'ai pas modifié l'état du réseau (IE à l'origine sur WiFi, si je désactive le WiFi et que je passe à Mobile Data, les messages arrivent bien). Une fois que j'ai modifié l'état du réseau, les messages commencent à arriver parfaitement, et il en va de même lorsque je rétablis l'état du réseau tel qu'il était avant (dans ce cas, WiFi), les messages continuent d'être reçus.

Le projet lui-même inclut la possibilité de démarrer au démarrage (démarre GCMBaseIntentService au démarrage), ce qui fonctionne à nouveau parfaitement et je suis sûr que l’app/service est en cours d’exécution car j’ai démarré manuellement l’application lorsque ce problème se produit vérifie également si le service est en cours d’exécution, et si ce n’est pas le cas, il l’exécute et vérifie s’il est enregistré).

Quelqu'un d'autre a-t-il rencontré ce problème ou a-t-il des indications sur la manière dont je pourrais le résoudre? Je ne vois aucune aide importante dans le journal entre l'heure à laquelle les messages ne sont pas reçus et l'heure à laquelle ils sont reçus (après avoir modifié l'état du réseau). J'ai parcouru les documents GCM et je ne vois aucune mention de messages non reçus en raison d'un délai d'attente (sur le périphérique lui-même), ni aucune option de configuration susceptible de l'affecter.

Appréciez toute aide - je peux fournir une source si besoin est, même si elle diffère à peine de l'application de démonstration fournie dans Android-sdk.

39
Seidr

J'ai aussi remarqué cela. Bien que je n’ai pas encore fouillé dans le code, voici pourquoi j’ai compris cela.

GCM (et la plupart des services de messagerie Push) fonctionne en laissant un socket de longue durée ouvert au serveur de notification Push de Google. Le socket est maintenu ouvert en envoyant des messages de "pulsation" entre le téléphone et le serveur. 

De temps en temps, l'état du réseau peut changer et ce socket sera cassé (parce que l'adresse IP du périphérique change, de 3g à wifi, par exemple). Si le message arrive avant que le socket ne soit rétabli, le périphérique ne le recevra pas immédiatement. 

La reconnexion ne se produit que lorsque le téléphone s'aperçoit que la prise est cassée, ce qui ne se produit que lorsqu'il tente d'envoyer un message de pulsation.

Encore une fois, juste ma compréhension de base de la façon dont cela fonctionne et pourquoi cela se produit, et je peux me tromper.

36
theelfismike

Les retards de message GCM ont plusieurs causes. Si un message commence à arriver après que vous ayez modifié l'état du réseau ou activé ou désactivé le mode avion, la cause la plus probable est un réseau qui ferme la connexion sans envoyer de message FIN/RST.

GCM maintient une connexion de longue durée - et se reconnecte s'il sait que la connexion a été rompue. Un routeur/AP/NAT est supposé envoyer un FIN ou un RST pour mettre fin à la connexion TCP - de sorte que GCM et les serveurs sachent que la connexion est interrompue.

Cependant, un certain nombre de routeurs et d’opérateurs de téléphonie mobile ne le font pas. GCM doit alors s’appuyer sur les pulsations, ~ 15 min en Wifi, davantage sur les réseaux mobiles. Il y a un compromis entre la durée de vie de la batterie/l'utilisation du réseau et la fréquence cardiaque. 

19
Costin Manolache

Selon votre commentaire dans la réponse ci-dessus et selon mon expérience avec les notifications Push de GCM, il n'y a aucune raison pour que si le réseau (connexion Internet) est disponible, vous ne devriez pas recevoir de notifications Push. Je vérifie toujours la disponibilité de la connexion Internet avant d'exécuter l'application pour les notifications Push comme ceci, essayez de vérifier si cela est vrai, vous devriez recevoir des notifications Push

    private boolean isNetworkAvailable() {
    ConnectivityManager connectivityManager 
          = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null;
}
1
Android Fanatic

alors, si la pensée @theelfismike est vraie, puis-je utiliser quelque chose comme 

  ConnectivityManager cm = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (null != activeNetwork) {
        if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
           // here the network changed to Wifi so I can send a heartbeat to GCM to keep connection

        if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
          //here the network changed to mobileData so I can send a heartbeat to GCM to keep connection
    }

ma solution est-elle bonne? 

0
Esmaeel Ibraheem