phonegap / phonegap-plugin-push

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

iOS registration happens before opting in #846

Open ghost opened 8 years ago

ghost commented 8 years ago

Expected Behaviour

When PushNotification.init() is called, the user is given a popup to accept/decline push notifications. The plugin should wait until they're accepted before registering. If they decline, it shouldn't register.

Actual Behaviour

As soon as the popup is shown, the registration event fires and the user is opted-in - even if they decline they still receive notifications

Reproduce Scenario (including but not limited to)

  1. Create a new project ( cordova create test )
  2. Add the iOS platform ( cordova platform add ios )
  3. Add the push plugin ( cordova plugin add phonegap-plugin-push --variable SENDER_ID=anything )
  4. Run on an iOS device ( cordova build ios && cordova run ios )
  5. Call the push notification code:
var instance = PushNotification.init( {
            android: {
                senderID: 5
            },
            ios: {
                alert: "true",
                badge: "false",
                sound: "true"
            },
            windows: {}
        } );

instance.on( 'registration', function(){console.log('registered')} );

Platform and Version (eg. Android 5.0 or iOS 9.2.1)

iOS 9.3.2 and 9.3.1

Cordova CLI version and cordova platform version

Cordova 6.0.0 iOS 4.0.1

Plugin version

1.6.3

macdonst commented 8 years ago

@joecmfa are you testing this on a device or simulator?

ghost commented 8 years ago

Two devices - one iPhone 6s running on 9.3.2 beta 2, and an iPhone 6 running 9.3.1

JumaBok commented 8 years ago

I'm experiencing the same issue. I have created a clean cordova project (cordova 6.1.1), added the ios platform (4.1.1), added the push notification plugin (1.6.3) and then used your example code when the device is ready.

I have created an app ID with push notification entitlements for sandbox/development and have assigned the provisioning profile and code signing entities correctly.

I then get the following logged when the popup requesting push notification opt-in appears:

2016-05-02 09:32:30.998 xxx[547:143864] Received Event: deviceready 2016-05-02 09:32:31.031 xxx[547:143920] Push Plugin register called 2016-05-02 09:32:31.031 xxx[547:143920] PushPlugin.register: setting badge to false 2016-05-02 09:32:31.032 xxx[547:143920] PushPlugin.register: clear badge is set to 0 2016-05-02 09:32:31.032 xxx[547:143920] PushPlugin.register: better button setup 2016-05-02 09:32:31.032 xxx[547:143920] GCM Sender ID (null) 2016-05-02 09:32:31.033 xxx[547:143920] Using APNS Notification 2016-05-02 09:32:32.077 xxx[547:143864] Push Plugin register success: <7a62fc69 869dd842 5d794ff1 079e12d8 215f9d9a 3253da9c 09395e8b 469f7e7a> 2016-05-02 09:32:32.124 xxx[547:143864] REGISTERED CORRECTLY 2016-05-02 09:32:32.125 xxx[547:143864] {"registrationId":"7a62fc69869dd8425d794ff1079e12d8215f9d9a3253da9c09395e8b469f7e7a"}

I can then press "Don't Allow" OR "OK". Pressing either then gives me the following additional entries in the log:

2016-05-02 09:32:35.067 xxx[547:143864] active 2016-05-02 09:32:35.067 xxx[547:143864] PushPlugin skip clear badge

If I send the token to my push system, and push a message to it, it gets disabled as an invalid token.

I would really appreciate some assistance.

Thanks

danielcrk-cn commented 8 years ago

I've notieced the same thing, push.on('registration') gets fired directly after init, and I can't find a way to know when the user has made their choice.

I'd like to check PushNotification.hasPermission AFTER the permission alert dialog. Does anyone know of a workaround?

fjordansilva commented 8 years ago

+1

mikechamberlain commented 8 years ago

+1, exactly the same thing happens for me on every one of my iOS test devices, which include iPhone6, 6S, iPad mini, iPad Pro. They are all running either 9.3 or 9.3.2.

As described above, I am also returned a device token immediately upon init(), before the user has made their preference from the modal. If I try to register this device token with the APNS at this point then it is rejected.

Assuming that the user allows push, the second time the app loads I try to register again. This time, the device token is accepted and notifications can be received.

There has to be something wrong here!

kenvunz commented 8 years ago

surprised me too, but apparently it's a normal thing http://stackoverflow.com/questions/15510190/apns-didregisterforremotenotifications-called-before-user-allows-notifications-o

macdonst commented 8 years ago

@kenvunz thanks for that link. I will mention it in the docs.

ds8k commented 8 years ago

@macdonst is there no event that fires after the user picks an option on the notifications dialog prompt? I've noticed that if I wait a bit before selecting "Okay" the registration event fires again, however it only fires the one time after init if I pick "Okay" quickly.

kd8ssq commented 6 years ago

@ds8k did you ever figure out if there was an event that fires after the user selects "Allow" or "Don't Allow"?

kd8ssq commented 6 years ago

@macdonst I'm running into this same issue. On new app installs, if a user doesn't click "Allow" or "Don't Allow" as soon as the dialog pops up, my code in my "registration" function is being fired with improper data (I can hack it by wrapping it in a timeout).

NM.pushNotification.on('registration', function(data) {
    //setTimeout(function() {
        NM.push.id = data.registrationId;

        PushNotification.hasPermission(function(data) {        
            NM.push.enabled = data.isEnabled;
            NM.fn.updatePushRegistration();
        });
    //}, 10000);

    // ensure badge count is cleared
    NM.fn.updateBadgeCount();
});

In looking at the output log in Xcode when running the app for the first time, if I wait till my app is completely loaded and then click either "Allow" or "Don't Allow" I see 2 lines show up in the log.

When I scan the code for phonegap-push-plugin, I see that is being fired in AppDelegate+notification.m in pushPluginOnApplicationDidBecomeActive. So my question is, since this is fired once someone approves or rejects notifications (I know it doesn't tell you which they picked), could a hook be written into here to fire the code that would save off the registration id on our servers?

macdonst commented 6 years ago

@kd8ssq would you just do something like:

NM.pushNotification.on('registration', function(data) {
        NM.push.id = data.registrationId;

        PushNotification.hasPermission(function(data) {        
            NM.push.enabled = data.isEnabled;
            if (NM.push.enabled) {
                NM.fn.updatePushRegistration();
           }
        });

    // ensure badge count is cleared
    NM.fn.updateBadgeCount();
});

So that you only send the registration ID to the server when the user allows it?

kd8ssq commented 6 years ago

@macdonst yes you could do something like that. I wasn't pasting my code to show a problem with the code, just what I want to run after the user clicks "Approve" or "Don't Approve" in the push notification dialog.

Right now there's nothing in place to let you know when the push notification dialog has been closed and I was wondering if a hook could be put in place in the function above to allow for handling after the dialog closes.

macdonst commented 6 years ago

@kd8ssq to the best of my knowledge there is no event fired from iOS when the user clicks "accept" or "deny" to dismiss the dialog.

kd8ssq commented 6 years ago

@macdonst In looking at the output log in Xcode when running the app for the first time, if I wait till my app is completely loaded and then click either "Allow" or "Don't Allow" I see 2 lines show up in the log.

When I scan the code for phonegap-push-plugin, I see that is being fired in AppDelegate+notification.m in pushPluginOnApplicationDidBecomeActive. So my question is, since this is fired once someone approves or rejects notifications (I know it doesn't tell you which they picked), could a hook be written into here to fire the code that would save off the registration id on our servers?

macdonst commented 6 years ago

@kd8ssq well that is because the app is in the background while the system permission dialog is displayed. Once the dialog is dismissed the application comes to the foreground and pushPluginOnApplicationDidBecomeActive is called. This same method would get called if you switched to another app and back to the one with the push plugin.

Theoretically, we could fire a registration event every time the app comes to the foreground but that seems a bit odd.

joshoconnor89 commented 5 years ago

+1

yyl000000 commented 5 years ago

@kd8ssq would you just do something like:

NM.pushNotification.on('registration', function(data) {
        NM.push.id = data.registrationId;

        PushNotification.hasPermission(function(data) {        
            NM.push.enabled = data.isEnabled;
            if (NM.push.enabled) {
                NM.fn.updatePushRegistration();
           }
        });

    // ensure badge count is cleared
    NM.fn.updateBadgeCount();
});

So that you only send the registration ID to the server when the user allows it?

I tried something similar. The problem is, since a user can take several seconds to accept/deny the permission, we don't know exactly how long we should wait before checking hasPermission() again. In the sample code above, it is checking it right after the registration event is fired, and that is most likely before the user has the chance to respond to the permission dialog box, and hasPermission() would return false. That's the problem I am facing, using a similar implementation as the sample code above.