39 votes

Google Cloud Messaging - les messages ne sont parfois pas reçus tant que l'état du réseau n'a pas changé

En travaillant sur un petit projet qui s'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 jusqu'à ce que j'aie changé l'état du réseau (c'est-à-dire, à l'origine en WiFi, si je désactive le WiFi et passe aux données mobiles, les messages arrivent bien). Après avoir changé l'état du réseau, les messages commencent à arriver parfaitement bien, et il en va de même lorsque je change l'état du réseau pour revenir à ce qu'il était avant (dans ce cas, WiFi), les messages continuent à être reçus.

Le projet lui-même inclut la possibilité de démarrer au démarrage (lance le GCMBaseIntentService au démarrage), ce qui fonctionne à nouveau parfaitement, et je suis sûr que l'application / le service est en cours d'exécution car j'ai démarré manuellement l'application lorsque ce problème se produit (qui vérifie également si le service est en cours d'exécution, et si ce n'est pas le cas, il le lance 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 de le résoudre ? Je ne vois rien d'utile dans le journal entre le moment où les messages ne sont pas reçus et celui où ils le sont (après avoir modifié l'état du réseau). J'ai parcouru la documentation de GCM et je ne vois aucune mention de messages non reçus en raison d'un délai d'attente (sur l'appareil lui-même), ou d'options de configuration qui pourraient affecter cela.

J'apprécie toute aide - je peux fournir les sources si nécessaire, bien que cela ne s'écarte guère de l'application de démonstration fournie dans l'Android-sdk.

36voto

theelfismike Points 1158

Je l'ai également remarqué. Bien que je n'aie pas creusé dans le code réel, voici ce que je comprends de la raison pour laquelle cela se produit.

GCM (et la plupart des services de messagerie push) fonctionne en gardant un socket de longue durée ouvert sur le serveur de notification push de Google. La prise est maintenue ouverte par l'envoi de messages "heartbeat" entre le téléphone et le serveur.

Occasionnellement, l'état du réseau peut changer et cette prise sera interrompue (parce que l'adresse IP de l'appareil change, de 3g à wifi, par exemple). Si le message arrive avant que la connexion ne soit rétablie, l'appareil ne recevra pas immédiatement le message.

La reconnexion ne se produit que lorsque le téléphone s'aperçoit que la prise est rompue, ce qui ne se produit que lorsqu'il essaie d'envoyer un message de battement de cœur.

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

20voto

Costin Manolache Points 151

Les retards dans la transmission des messages du GCM peuvent avoir de nombreuses causes. Si les messages commencent à arriver après un changement d'état du réseau, ou après avoir activé ou désactivé le mode avion, la cause la plus probable est un réseau qui ferme la connexion sans envoyer de FIN/RST.

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

Cependant, un certain nombre de routeurs et d'opérateurs de téléphonie mobile ne le font pas, et GCM doit alors s'appuyer sur le battement de cœur, ~15 min sur le Wifi, plus sur le mobile. Il y a un compromis entre la durée de vie de la batterie/l'utilisation du réseau et la fréquence des battements de cœur.

1voto

Android Fantastic Points 1320

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 vous ne receviez pas les notifications push si le réseau (connexion internet) est disponible. 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 ceci si c'est vrai vous devriez recevoir les notifications push.

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

0voto

Donc, si la pensée de @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 ?

-4voto

user1918096 Points 44

Dans la classe GCMIntentSevice, lorsque vous recevez un message du serveur, la méthode onMessage est appelée, ce qui vous permet de faire quelque chose comme...

PowerManager pm = (PowerManager) getApplicationContext()
                .getSystemService(Context.POWER_SERVICE);
        WakeLock wakeLock = pm.newWakeLock(
                        (PowerManager.SCREEN_BRIGHT_WAKE_LOCK
                                | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP),"TAG");
        wakeLock.acquire();

et vous devez ajouter

<uses-permission android:name="android.permission.WAKE_LOCK" /> dans votre fichier manifeste.

ceci devrait faire l'affaire...

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