34

I've been reading many posts regarding a GCM issue that affects some people. It seems that in some devices/routers/carriers the notifications suffer delays. I've experienced this issue with my router: messages came with a lot of delay on WIFI but came instantly when I disabled WIFI and connected to the mobile net.

It seems there is a workaround that can be done from the Android app. Something like increasing the heartbeat that keeps GCM connection alive, or so.

Can anyone tell us what should we do to avoid the delay? How can we keep the connection with GCM from an Android app? A code example (and where and how to use it) would be really helpful.

This post explains the problem. It says that "we could keep the connection alive with a ping every two minutes from the GCM server (which is free)". How can we do that?

Thanks a lot


The following apps seem to do the trick. Surprisingly, the first one doesn't need any permission, the second one internet connection and the third one is only for rooted phones:

https://play.google.com/store/apps/details?id=at.pansy.droid.gcmWifiFix

https://play.google.com/store/apps/details?id=com.elotro.pushheartbeat

https://play.google.com/store/apps/details?id=com.andqlimax.pushfixer

Eran
  • 387,369
  • 54
  • 702
  • 768
Ferran Maylinch
  • 10,919
  • 16
  • 85
  • 100
  • This is most likely caused by the unrealistic heartbeat intervals in GCM/FCM. Please consider https://pushy.me, an alternative push notification gateway that greatly improves notification speed & reliability on Android (Full disclosure - I founded Pushy). – Elad Nava Jul 17 '18 at 11:30

5 Answers5

37

I would put this as a comment in the first answer but I don't have enough reputation.

I had a similar issue and I solved it executing the code below before calling my webservice.

context.sendBroadcast(new Intent("com.google.android.intent.action.GTALK_HEARTBEAT"));
context.sendBroadcast(new Intent("com.google.android.intent.action.MCS_HEARTBEAT"));

Hope it help you!

Renan Grativol
  • 1,062
  • 15
  • 20
  • Anywhere you have access to the context object (Application, Activity, Service). For instance, If you use it inside your activity just call getContext() and use the code above. – Renan Grativol Aug 10 '15 at 15:55
  • Is it possible to do this with cordova? – Dr.Knowitall Jan 11 '16 at 07:03
  • Does not work on my Samsung Note 4 , but works perfectly on all the other devices I checked (about 10 devices from different vendors). – FunkSoulBrother Jan 11 '16 at 10:38
  • @RenanGrativol Hi, I am facing same issue, can i use above code in my Singleton class ? with this reference ? `this.sendBroadcast(new Intent("com.google.android.intent.action.GTALK_HEARTBEAT")); tihs.sendBroadcast(new Intent("com.google.android.intent.action.MCS_HEARTBEAT"));` – Chintan Khetiya Apr 30 '16 at 04:23
  • If you have access to these methods , so, yes. Anywhere you have access to the context object (Application, Activity, Service etc...) – Renan Grativol Apr 30 '16 at 20:47
  • how about your application is killed by the system, so you can't fix its heartbeat interval through send broadcast, but you need your user receives a real-time message. – Jacks Gong Sep 20 '17 at 07:13
10

There's no need to send the heartbeat from the GCM server to the phone, you can force android itself to send the heartbeat sooner that it would otherwise do.

I had a look at the Push Notifications Fixer app, which I tested and worked for me, and it seems all you need to do is broadcast the following intents:

com.google.android.intent.action.MCS_HEARTBEAT
com.google.android.intent.action.GTALK_HEARTBEAT

I'm not sure why it's sending both, you can try only one and see if it does the trick. Here's the link to the app (I'm not the developer): https://play.google.com/store/apps/details?id=com.andqlimax.pushfixer.noroot

sorin.silaghi
  • 465
  • 6
  • 21
2

An alternative solution if you have root permissions - You can check and change the GCM heartbeat times manually. The default is 900000 (15 minutes). I set to 240000 (4 minutes) to be safe and avoid 5 minute router timeouts.

Check heartbeat time (shell)

adb shell
su
sqlite3 /data/data/com.google.android.gsf/databases/gservices.db "SELECT * FROM main WHERE name ='gtalk_max_server_heartbeat_time';"
sqlite3 /data/data/com.google.android.gsf/databases/gservices.db "SELECT * FROM main WHERE name LIKE 'gtalk_%heartbeat_ping_interval_ms';"

Change heartbeat time (shell)

sqlite3 /data/data/com.google.android.gsf/databases/gservices.db "UPDATE main SET value = '240000' WHERE name = 'gtalk_max_server_heartbeat_time'
sqlite3 /data/data/com.google.android.gsf/databases/gservices.db "UPDATE main SET value = '240000' WHERE name LIKE 'gtalk_%heartbeat_ping_interval_ms'

Change heartbeat time (Android)

Process proc = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(proc.getOutputStream());
os.writeBytes("sqlite3 /data/data/com.google.android.gsf/databases/gservices.db \"UPDATE main SET value = '240000' WHERE name = 'gtalk_max_server_heartbeat_time'\"\n");
os.writeBytes("sqlite3 /data/data/com.google.android.gsf/databases/gservices.db \"UPDATE main SET value = '240000' WHERE name LIKE 'gtalk_%heartbeat_ping_interval_ms'\"\n");
os.writeBytes("exit\n");
os.writeBytes("exit\n");
os.flush();
os.close();
proc.waitFor();
Greg T
  • 3,278
  • 3
  • 37
  • 39
2

It's not about how you receive the push, it's about how you send it.

You can set the priority of the message to "high" ( From where you send the push, your server )

https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message

dam1
  • 3,536
  • 3
  • 22
  • 18
  • This worked for me, and seems to apply to FCM as well, I have a feeling the other answers are outdated? – JMK Aug 29 '17 at 12:05
1

"we could keep the connection alive with a ping every two minutes from the GCM server (which is free)". How can we do that?

You can do that by sending a GCM message from your server to all the devices on which you wish this ping to be performed. You can put some special payload in that message that would be processed silently by the app on the device (and not display any notification). However, such ping will shorten the battery life of the devices that use this app.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Thanks Eran. We can't do that because we would have to send too many notifications -- we have millions of registered devices. Can we do the "ping" from the device (from the Android app)? – Ferran Maylinch Oct 25 '13 at 10:55
  • 1
    @FerranMaylinch That might be possible. I've never tried to send a notification from a device to itself, but there's no reason it shouldn't work (after all the device has its own registration ID and all it has to do is post an HTTP request to the GCM server). The only problem with that is that it will only work when the app is running. – Eran Oct 25 '13 at 19:25