studio notificaciones fcm app android google-cloud-messaging android-networking

fcm - notificaciones push android php



Google Cloud Messaging: mensajes que a veces no se reciben hasta que el estado de la red cambia (5)

Mientras trabajo en un pequeño proyecto que se integra con GCM, me encontré con un problema extraño.

Algunas veces, cuando empiezo a mirar el registro para ver si recibo los mensajes, parece que no aparecen los mensajes hasta que cambie el estado de la red (IE originalmente en WiFi, si apago WiFi y paso a Mobile Data, llegan los mensajes multa). Después de haber cambiado el estado de la red, los mensajes comienzan a llegar perfectamente bien, y lo mismo se aplica una vez que cambio el estado de la red a lo que era antes (en este caso, WiFi) los mensajes continúan recibiéndose.

El proyecto en sí mismo incluye la capacidad de iniciar al arrancar (inicia el GCMBaseIntentService en el arranque), que de nuevo funciona perfectamente bien, y estoy seguro de que la aplicación / servicio se está ejecutando como inicié manualmente la aplicación cuando ocurre este problema (que también verifica si el servicio se está ejecutando, y si no lo está, lo ejecuta y verifica si está registrado).

¿Alguien más se ha encontrado con este problema, o tiene alguna sugerencia sobre cómo podría resolver esto? No veo nada de mucha ayuda en el registro entre el momento en que no se reciben los mensajes y cuándo (después de cambiar el estado de la red). He revisado los documentos de GCM y no puedo ver ninguna mención de los mensajes que no se reciben debido a un tiempo de espera (en el dispositivo mismo) o cualquier opción de configuración que pueda afectar esto.

Aprecie cualquier ayuda: puedo proporcionar la fuente si es necesario, aunque apenas se desvía de la aplicación de demostración provista en android-sdk.


Hay muchas causas de retrasos en los mensajes de GCM. Si el mensaje comienza a llegar después de cambiar el estado de la red o el modo de conexión / desconexión del avión, la causa más probable es una red que cierra la conexión sin enviar FIN / RST.

GCM mantiene una conexión duradera, y se reconecta si sabe que la conexión se ha roto. Se supone que un enrutador / AP / NAT envía un FIN o RST para finalizar la conexión TCP, por lo que GCM y los servidores sabrán que la conexión está muerta.

Sin embargo, varios enrutadores y operadores móviles no hacen esto, y luego GCM necesita confiar en el latido del corazón, ~ 15 min en Wifi, más en el móvil. Existe un intercambio entre la duración de la batería / uso de la red y la frecuencia del latido.


Me he dado cuenta de esto también. Aunque no he profundizado en el código real, aquí está mi comprensión de por qué sucede esto.

GCM (y la mayoría de los servicios de mensajería instantánea) funciona manteniendo un socket de larga duración abierto al servidor de notificaciones automáticas de Google. El socket se mantiene abierto al enviar mensajes de "latido" entre el teléfono y el servidor.

Ocasionalmente, el estado de la red puede cambiar y este socket se romperá (debido a que la dirección IP del dispositivo cambia, de 3g a wifi, por ejemplo). Si el mensaje aparece antes de que se restablezca el socket, entonces el dispositivo no recibirá el mensaje de inmediato.

La reconexión solo ocurre cuando el teléfono detecta que el socket está roto, lo que solo ocurre cuando intenta enviar un mensaje de latido.

De nuevo, solo mi comprensión básica de cómo funciona y por qué sucede, y podría estar equivocado.


Según su comentario en la respuesta anterior y de acuerdo con mi experiencia con notificaciones push GCM no hay ninguna razón para que si la red (conexión a internet) está disponible no debería recibir notificaciones push. Siempre controlo la disponibilidad de conexión a internet antes de ejecutar la aplicación para notificaciones push así, intente marcar esto si esto es cierto, debería recibir notificaciones push

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


en la clase GCMIntentSevice, cuando recibes un mensaje del servidor, se llama al método onMessage para que en ese momento puedas hacer algo como ...

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

y tienes que agregar

<uses-permission android:name="android.permission.WAKE_LOCK" /> permiso en su archivo de manifiesto ...

Esto debería funcionar...


entonces, si el pensamiento de @theelfismike es verdadero, puedo usar algo como:

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 }

es mi solución buena?