ToothlessGear / node-gcm

A NodeJS wrapper library port to send data to Android devices via Google Cloud Messaging
https://github.com/ToothlessGear/node-gcm
Other
1.3k stars 206 forks source link

High priority message doesn't wake device up #231

Closed hyperh closed 8 years ago

hyperh commented 8 years ago

I'm sending a high priority message to my Android device, however after a long period of inactivity of the app on my phone (a few hours), I don't receive GCM messages. Even after I go back into the app, I don't receive that message. I do receive confirmation that the message was sent from the server though, there's just no receipt of it on the Android device.

EDIT: Just to clarify, I do receive notifications fine (both normal and priority), but only in the case when the app is open or was just closed (i.e. put into the background) at most 2 hours or so ago.

Some of my code is below:

        const regToken = user.GCMToken.token;
        const apiKey = Meteor.settings.GCM.server_api_key;

        let message = new gcm.Message({
          priority: 'high',
          data: {
            teamId,
            convoId,
            convoName,
            text,
          },
        });

        const regTokens = [ regToken ];

        // Set up the sender with you API key
        var sender = new gcm.Sender(apiKey);

        console.log(`----------`);
        console.log(new Date(), SEND_GCM_MSG);
        // Now the sender can be used to send messages
        sender.send(message, { registrationTokens: regTokens }, function (err, response) {
          if (err) { console.error(err); }
          else { console.log('response', response); }
        });
hypesystem commented 8 years ago

Priority has no effect on Android, it is an argument for sending GCM messages to iOS devices.

This sounds like a client-side issue, and you should ask the question on StackOverflow or similar.

You probably just need to properly set up a receiving service in the app. I hope you figure it out! Good luck :-)

eladnava commented 8 years ago

@hypesystem Looks like with the new Android 6.0 Doze feature, Android devices do respond differently to priority:

If your Android users must see a notification right away, make sure to use a GCM high priority message. http://developer.android.com/training/monitoring-device-state/doze-standby.html

hypesystem commented 8 years ago

Wow, okay -- that is new! My bad.

hyperh commented 8 years ago

@hypesystem Just to clarify, I do receive notifications fine (both normal and priority), but only in the case when the app is open or was just closed (i.e. put into the background) at most 2 hours or so ago.

When I haven't interacted with the app in a while, I stop receiving any type of notification.

hypesystem commented 8 years ago

It sure seems weird! I am still pretty sure it is a client-side problem, as the code you are using above looks fine. I read the doze documentation, and it seems that you are doing the right thing. I don't know the solution -- keep us posted, if you figure it out!

govardhanaraoganji commented 8 years ago

High priority issue.

Am also facing same issue from past 3 days onwards.Please help me ASAP.

Here is my snippet code have a look, var gcm = require('node-gcm');

var message = new gcm.Message({ collapseKey: 'demo', // priority: 'high', contentAvailable: true, delayWhileIdle: true, timeToLive: 3, delay_while_idle: true, // restrictedPackageName: "somePackageName", dryRun: true, data: { 'key1': "testnodegcm." }, notification: { title: "From node app server.", icon: "ic_launcher", body: "This is a notification that will be displayed ASAP." }

}); var sender = new gcm.Sender('API KEY'); var registrationTokens = [ "fYINc8tbFIo:APA91bHmnfVTd2rMzSB3zC6Kg4yvImEdeAQHR1CWg-gIvxr-wOprAdTREgOUJ1wXPPvCGSPoKFZ6I8LWFDwgH4OpryBqJJcH7nYkpLNUio5hblCzgVPKkPvOueKkIX5kHKYm4TYCCH5e" ]; sender.sendNoRetry(message, registrationTokens[0] //registrationTokens // { registrationTokens: registrationTokens } , function(err, data) { if (err) { // handle error console.log("error", err); } else { // do something console.log("data", data); } });

Am trying with all possibilities.

eladnava commented 8 years ago

@govardhanraoganji If things stopped working in the past 3 days and you haven't touched anything, it might be an issue with GCM itself, either not honoring the priority you specify or possibly even rate-limiting the number of push notifications with high priority.

Last but not least, let's not rule out the fact that the device might not be connected to GCM for some reason when in doze mode -- either due to battery-saving, network-killing apps, or a router that disconnects idle connections.

Try on a clean device and on a different wireless network/carrier to isolate the issue.

govardhanaraoganji commented 8 years ago

@eladnava i apologize, code working fine but i made mistake in gcm.Message options i.e) dryRun: true because of "true", GCM is checking the configuration setup / options right or wrong only.

Follow the link, http://stackoverflow.com/questions/25885830/google-cloud-messaging-fake-message-id :+1:

http://stackoverflow.com/questions/32344720/http-post-request-to-gcm-server-always-returning-notregistered :+1:

Thank you for sharing your comments & its given boosters to me :)

Edujugon commented 8 years ago

@hyperh could you solve the issue you were facing? I'm also stuck with the notification reception when the app is in doze mode...

hyperh commented 8 years ago

@edujugon I wasn't able to resolve it consistently. It works sometimes and other times does not :(

Edujugon commented 8 years ago

Thanks @hyperh I'll continue researching :)

eladnava commented 8 years ago

It would appear that GCM has its own underlying logic on whether to deliver your high priority message to a device in Doze mode. Google has probably implemented some kind of rate-limiting algorithm that will prevent your server from waking up the device too many times in a short period of time if your app is rarely used on the device, and/or based on other parameters.

Since this is outside the scope of node-gcm, I am obliged to close this. Please let us know if you are able to find a way around this behavior.

miparnisari commented 7 years ago

I've been having this issue in Production as well (I cannot reproduce it locally).

According to the Firebase HTTP Protocol docs, the parameter delay_while_idle has been deprecated on Nov 15th 2016, it will be accepted by FCM, but ignored. It specifies that "the message should not be sent until the device becomes active." (I've no idea what "active" means BTW)

Could this be the culprit?

eladnava commented 7 years ago

@miparnisari Probably not, because the documentation mentions that this parameter is ignored, so it cannot be what is causing this behavior.

There are two possible causes, in my opinion, for what you are experiencing: 1) GCM rate limiting, as I mentioned in https://github.com/ToothlessGear/node-gcm/issues/231#issuecomment-251092293 2) Unrealistic GCM heartbeat intervals which cause the underlying socket to be disconnected passively by mobile carriers / Wi-Fi routers: https://eladnava.com/google-cloud-messaging-extremely-unreliable/#unrealisticgcmheartbeatinterval

It's worth mentioning that to overcome this issue with unreliable GCM notifications in my own apps two years ago, I developed a highly-reliable push notification gateway called Pushy and made it available to any other developer who needed time-sensitive notification delivery. It is indeed an issue which many developers face with GCM and there seems to be no easy fix.

joshimohit commented 7 years ago

@eladnava Does pushy work even in Doze mode for Android N and on Chineese phones like MI, Gieonee in doze mode?

eladnava commented 7 years ago

@joshimohit On devices running Android 6.0+, Doze mode terminates all background connections when the phone is idle and not being charged, including the background connection to Pushy.

As soon as the device is moved or awoken by the user, background connections are restored and any pending notifications will be delivered within seconds, providing they have not expired yet.

To send notifications to devices in Doze mode, your app can declare the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission in its AndroidManifest.xml and display a system dialog that asks users to whitelist your app from battery optimizations without leaving the app.

This will effectively keep the background connection to Pushy active and devices will be able to receive notifications even in Doze mode.


Regarding your second question, indeed, some Chinese devices may not receive notifications when your app is in the background.

These phones have an Autostart feature in the System Settings which by default prevents apps from starting up on boot and running services in the background after being swiped away from the recent apps list: http://stackoverflow.com/questions/34104161/not-receiving-gcm-push-notification-in-mi-phone-if-app-is-killed

Popular apps such as WhatsApp and Facebook are pre-whitelisted in the settings. The solution would be to detect whether the user's device has this Autostart mechanism and ask the user to enable Autostart for your app.

The Autostart feature also affects your app's ability to receive GCM / FCM notifications, therefore, it is not a Pushy-specific limitation.

joshimohit commented 7 years ago

In case of chineese phone like MI, we have observed that FCM messages are not delivered even after giving auto start permission and app is in "battery not optimized" mode ? When phone comes out of doze mode, do Pushy guarantees the immidiate message delivery?

eladnava commented 7 years ago

Hi @joshimohit, In that case, it might be FCM rate-limiting or not respecting the priority: high parameter that you send in your notifications.

You can try to examine the logcat to see if MIUI is still terminating or preventing your app from receiving FCM notifications.

Regarding your second question, no push gateway can guarantee immediate delivery because of so many factors out of our control. However, from our experience, yes, notifications should arrive seconds after the device exits Doze mode.