phonegap / phonegap-plugin-push

Register and receive push notifications
MIT License
1.94k stars 1.91k forks source link

How to handle .init or token expiration when no network available to receive the token or notification? #1483

Open uj opened 7 years ago

uj commented 7 years ago

If .init is called when network is available, my app receives a device token, that is good.

However, if .init is called when network is not available (or the google service is not reachable for whatever reason), then obviously my app will not receive a device token, and I don't think that .init ever retries.

Also, I imagine the same situation would be an issue if google expires the device token, and then the device happens to have no network access when google sends a new device token, it will not receive the new token notification.

Should .init be automatically retrying to get an initial token if there is an error? And, similarly, should it automatically be checking to see if there is a new token available if it missed the new token notification for some reason?

Or should I be periodically calling .init myself to cover such instances?

fredgalvao commented 7 years ago

AFAIK, the plugin registers for an event that the internal APIs will trigger whenever a new registrationId is known, and the registration event from the plugin API will trigger on cascade from that, so that your application can be notified by it anytime. And for that root event to happen, I'm pretty sure GCM/FCM APIs will keep trying and keep control/state of connection, so that the whole flow works.

So, if you call .init() and .on('registration') properly on your app, you should be notified of any updates to the registrationId as soon as the underlying google API tells the plugin so.

Is that not the case? If you have a scenario that can reproduce a flaw in those expectations, please provide the steps and info so that we can debug it.

uj commented 7 years ago

If there is no network initially, the registration never happens even after the network comes back. Android 6.0 phonegap-plugin-push version 1.9.2 Cordova version 6.4.0

Steps to reproduce:

ionic start phonegap_sample blank --v2

Add the following to config.xml
  <plugin name="phonegap-plugin-push" spec="1.9.2">    
  <variable name="SENDER_ID" value="xxxxxxxxxxxx"/>   
  </plugin>

ionic platform add android

app.component.ts:
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import {StatusBar, Push, Splashscreen} from "ionic-native";

import { HomePage } from '../pages/home/home';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage = HomePage;

  constructor(platform: Platform) {
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      StatusBar.styleDefault();
      Splashscreen.hide();

var push = Push.init({
    android: {
        senderID: "xxxxxxxxxxxx"
    },
    ios: {
        alert: "true",
        badge: "true",
        sound: "true"
    },
    windows: {}
});

push.on('registration', function(data) {
    console.log("registration=" + data.registrationId)
});

push.on('notification', function(data) {
    // data.message,
    // data.title,
    // data.count,
    // data.sound,
    // data.image,
    // data.additionalData
});

push.on('error', function(e) {
    console.log("error=" + e.message)
});

    });
  }
}

TURN ON AIRPLANE MODE ON at the  PHONE, to stop all network activity.

ionic run android --prod

Watch the remote log in Chrome.
It shows "error=SERVICE_NOT_AVAILABLE" because of no network.

Turn AIRPLANE MODE off at the phone.

Keep watching log...  nothing else happens.  A registration ID never arrives.
fredgalvao commented 7 years ago

This class should receive an update whenever the underlying API gets a new value. I'm not sure what is causing your scenario not to be updated whenever connection is available again, so that might indeed be a bug.

fredgalvao commented 7 years ago

@macdonst You mind retesting this?

uj commented 7 years ago

No, the plugin cannot simply listen for a new value, that will not work. The plugin (or the application) must actively resend the registration request over and over until it gets a different response. The question is: Is this a responsibility of the phonegap plugin? Or do I need to implement that myself?

Below is the official documentation from Google:

https://developers.google.com/android/reference/com/google/android/gms/gcm/GoogleCloudMessaging

Constant Value: "SERVICE_NOT_AVAILABLE" = The device can't read the response, or there was a 500/503 from the server that can be retried later. The application should use exponential back off and retry.

fredgalvao commented 7 years ago

I see. InstanceIDListenerService has the goal of notifying changes to the registrationId, not the goal of notifying the current registrationId. I think you're right, and we'd need to at least create a listener to a network change event and retry once per app lifecycle, imo, when the first attempt fails.

uj commented 7 years ago

"Network change event" would only detect if there is a network connection to the phone, correct? If so, that would not account for upstream issues that would prevent the registration from occurring (for example if you have local network access but not access all the way to the google servers).

macdonst commented 7 years ago

@uj if you try to register when the device is off line you get a proper error event it is then up to you as the developer to re-try init when the network becomes available. You will get an updated registration even if the app is notified by Google that the registration ID has changed.

uj commented 7 years ago

@macdonst Thank you for your answer. That is what I am currently doing while waiting to find out officially if this is intended to be a feature of the plugin or not an intended feature.

It seems that your answer contradicts the last "imo" answer given by @fredgalvao.

I could not find anything in the documentation regarding this issue that perhaps many developers never run across during testing because they always have network access during testing, but it could be a major problem with real world users in various situations and create difficult troubleshooting.

fredgalvao commented 7 years ago

I got it wrong indeed, but I wouldn't say it was contradicting, but complementary. I just didn't know that I could call .init() multiple times to handle that.

I also agree we could put that on the docs.