Google Cloud Messaging - messages sometimes not received until network state changed

Solution 1:

I've noticed this as well. Although I haven't dug into the actual code, here's my understanding of why this happens.

GCM (and most push messaging services) works by keeping a long-lived socket open to Google's push notification server. The socket is kept open by sending "heartbeat" messages between the phone and server.

Occasionally, the network state may change and this socket will be broken (because the IP address of the device changes, from 3g to wifi, for example). If the message comes in before the socket is reestablished, then the device will not immediately get the message.

The reconnection only happens when the phone notices the socket is broken, which only happens when it tries to send a heartbeat message.

Again, just my basic understanding of how it works and why it happens, and I could be wrong.

Solution 2:

There are many causes for GCM message delays. If message start to arrive after you changed network state, or switched on/off airplane mode - the most likely cause is a network that closes the connection without sending FIN/RST.

GCM maintains a long-lived connection - and reconnects if it knows the connection was broken. A router/AP/NAT is supposed to send a FIN or RST to terminate the TCP connection - so GCM and servers will know the connection is dead.

However a number of routers and mobile operators don't do this, and then GCM needs to rely on the heartbeat, ~15 min on Wifi, more on mobile. There is a trade-off between battery life/network use and heartbeat frequency.

Solution 3:

As per your comment in above answer and according to my experience with GCM push notifications there isn't any reason that if network(internet connection) is available you should not receive push notifications I always check internet connection availability before running the application for push notification like this try checking this if this is true you should receive push notifications

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