Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

need way to set ECB callback without also registering device #314

Open
bwo opened this issue Sep 16, 2014 · 18 comments
Open

need way to set ECB callback without also registering device #314

bwo opened this issue Sep 16, 2014 · 18 comments

Comments

@bwo
Copy link

bwo commented Sep 16, 2014

as far as I can tell the only way to register the ECB callback is by calling register, which means that if the app is closed and starts up again, I'll have to call register again, even if I've already registered. However, it seems pretty clear from google's documentation that, at least for android, this behavior is undesirable:

On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.

It also means additional roundtrips both to Google and to the backend server to store the new id.

@RobbieElias
Copy link

What I ended up doing is making it so the actual GCM register function is only called on application start without actually changing any JavaScript code.

In the PushPlugin.java class, I changed the execute function like so:

    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {

        boolean result = false;

        Log.v(TAG, "execute: action=" + action);

        if (REGISTER.equals(action)) {

            Log.v(TAG, "execute: data=" + data.toString());

            try {

                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                if(!prefs.getBoolean("registered", false)) {

                    JSONObject jo = data.getJSONObject(0);

                    gWebView = this.webView;
                    Log.v(TAG, "execute: jo=" + jo.toString());

                    gECB = (String) jo.get("ecb");
                    gSenderID = (String) jo.get("senderID");

                    Log.v(TAG, "execute: ECB=" + gECB + " senderID=" + gSenderID);

                    GCMRegistrar.register(getApplicationContext(), gSenderID);
                    callbackContext.success();

                    // run your one time code
                    SharedPreferences.Editor editor = prefs.edit();
                    editor.putBoolean("registered", true);
                    editor.commit();
                }

                result = true;

            } catch (JSONException e) {
                Log.e(TAG, "execute: Got JSON Exception " + e.getMessage());
                result = false;
                callbackContext.error(e.getMessage());
            }

            if ( gCachedExtras != null) {
                Log.v(TAG, "sending cached extras");
                sendExtras(gCachedExtras);
                gCachedExtras = null;
            }

        } else if (UNREGISTER.equals(action)) {

            GCMRegistrar.unregister(getApplicationContext());

            Log.v(TAG, "UNREGISTER");
            result = true;
            callbackContext.success();
        } else {
            result = false;
            Log.e(TAG, "Invalid action : " + action);
            callbackContext.error("Invalid action : " + action);
        }

        return result;
    }

Basically I added an if statement that adds a shared preference to ensure the GCMRegistrar.register() function is only called once.

In my main application activity (under the package com.example.appname for example), I added an onDestroy function which will remove the shared preference when the application is closed.

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        if(prefs.getBoolean("registered", false)) 
        {
            SharedPreferences.Editor editor = prefs.edit();
            editor.remove("registered").commit();
        }
    }

Therefore, the register function will be called only when the app is first opened. Let me know if you need more info.

@bwo
Copy link
Author

bwo commented Sep 17, 2014

Ok, and I added a different method that I can call from JS that only sets the callback (so that I can also easily check for different app versions and register when I want to with the logic in the JS, which is the main development language of the app). (I also don't want to register every time the app is open, which is still too often.)

But I would rather not have to maintain a fork, you know?

@nacho-marin
Copy link

Aren't you planning a pull request to the project, campusgrids? It is an interesting patch...

@bwo
Copy link
Author

bwo commented Sep 18, 2014

with respect, that change is still wrong. There is no reason to re-register every time the app starts. Google docs are pretty clear about this. The same is true on iOS---re-registration is simply not necessary.

@RobbieElias
Copy link

Then when would a re-registration be necessary?

@bwo
Copy link
Author

bwo commented Sep 18, 2014

What's necessary is telling the plugin what callback to use.

@bwo
Copy link
Author

bwo commented Sep 18, 2014

Unless that's stored somewhere (which doesn't seem to be the case, looking through the source, though).

@RobbieElias
Copy link

If you implement it, would you be able to post your code?

@bwo
Copy link
Author

bwo commented Sep 18, 2014

I just have an extra case for the android version:

    public static final String SETECB = "setecb";

...

        } else if (SETECB.equals(action)) {
                    Log.v(TAG, "setecb: data=" + data.toString());
                    try {
                        JSONObject jo = data.getJSONObject(0);
                        gECB = (String) jo.get("ecb");
                        gSenderID = (String) jo.get("senderID");
                        result = true;
                        callbackContext.success();
                    } catch (JSONException e) {
                        Log.e(TAG, "setectb: Got JSON Exception " + e.getMessage());
                        result = false;
                        callbackContext.error(e.getMessage());
                    }
                } else if (UNREGISTER.equals(action)) {
...

Then I call this from the js. Ideally similar/equivalent functionality would be present for other platforms as well; the organization of the iOS code is different, though, and less transparent to me.

@sirajulm
Copy link

sirajulm commented Oct 5, 2014

@bwo I've been bothered about the same issue for a couple of days. When the app is installed, in forground, and backgorund modes the plugin works fine, but I will not be able to process any further notification I recieve after the app is exited.
After a lot of search I reached to this issue. I'm basically a web developer and I dont understand Java code here. It would be good if you could help to to figure out which code to be used, yours or from campusgrids.

@simoneb
Copy link

simoneb commented Oct 21, 2014

Indeed, some documentation about how this plugin should be used would be nice. According to Android's docs registration should only ever occur once and then when the application is updated, whereas this plugin apparently requires that registration is done every time that the app starts.
If that's really the case, then it should be documented somewhere, even if this behavior seems still wrong, as you should not need to register every time the application starts (which includes when it is woken up by a push notification).

@piovezan
Copy link

Guys, I'm new to submitting pull requests but have experience with Android, how can I help to get this issue fixed?
@simoneb You are right, Android's registration to the GCM service should be done once and then when the application is updated; however every time the app starts it will have to provide the callback function name (ECB) so @bwo's code is right in the native side and @hybridtechie's code in issue #418 seems to be in the right path in the javascript side. The setECB javascript function should be called every time the app starts (and before the callback is called evidently). This is necessary because the OS may kill the app's process anytime in order to free up memory therefore losing the callback name. An alternative would be persisting the callback name somewhere but I think setting it on app start is a more appropriate approach.

@DaniloCouto
Copy link

Let me complement @bwo's method...

gWebView = this.webView;

Add this line at his function
Now javascript code can get the notification array.

@kentmw
Copy link

kentmw commented Aug 12, 2015

If this helps anyone:
Checkout https://github.com/kentmw/PushPlugin, my fork that fixed this issue. Very similar to what people here have done. I've tested the equivalent fix for iOS and Android

specifically the commits:
kentmw@c577e15
kentmw@1e4ed10
and a small typo fix here:
kentmw@54bce03

@kishorpawar
Copy link

Guys I was also struggling like you all, and somehow @kentmw 's suggestion helped me to get this working. I have documented the changes here http://stackoverflow.com/questions/32166357/customizing-pushplugin-for-cordova-for-android/32166358#32166358

@anilbhanushali
Copy link

So will this fix by @kishorpawar be pulled into this repo ??

@kishorpawar
Copy link

@anilbhanushali I haven't actually fixed this issue, the fixes are by @kentmw, I just figured out what more needs to be done besides @kentmw changes and documented on @stackoverflow, so that nobody needs to struggle more.
and more shocking is even @kentmw 's changes haven't been merged in original repo.

@pleivac
Copy link

pleivac commented Aug 26, 2015

It works great on Android! Thank you @kentmw!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests