Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate Push Notification using Azure Push Notification

  • We are implementing Push Notification System for iOS & Android using Azure Notification Hub.

  • App registers every time during app launch. Devices are registered for push notification with tags identified by appname_userid. For e.g. Android_1122 where 1122 is an unique user id. The same in an iPhone device will be iPhone_1122. A user can have multiple devices, where a push message will be meant to be delivered to all devices having the same tag.

  • However there is an issue that we are facing on duplicate push notifications getting delivered for a few users. Every time a user uninstall & re-installs the app, a new token is returned. So, for that given tag, multiple registrations are made leading to duplicate pushes delivered to the same device.

  • Have also gone through similar links like the one below. But, not entirely clear as to what is exactly meant by using the Create Registration ID REST API that returns a registrationId without actually creating a registration. azure notification hubs - app uninstall

  • Please provide some way to avoid duplicate registrations for the same device.

Below is the code we are using to register.

iOS Devices

NSString *mobileServicesURL = @"Endpoint=sb://mobilepushnotificationhub.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=XXXXXXXXXXXXXXXXX=";

SBNotificationHub *hub = [[SBNotificationHub alloc] initWithConnectionString:mobileServicesURL notificationHubPath:@"notificationhubname"];

[hub registerNativeWithDeviceToken:token tags:[NSSet setWithObjects:[NSString stringWithFormat:@"iphoneapp_%@", [self getUserID]], nil] completion:^(NSError* error) {
    completion(error);
}];

Android Devices

private void gcmPush() {
    NotificationsManager.handleNotifications(this, SENDER_ID, MyHandler.class);

    gcm = GoogleCloudMessaging.getInstance(this);

    String connectionString = "Endpoint=sb://mobilepushnotificationhub.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXX=";

    hub = new NotificationHub("notificationhubname", connectionString, this);

    registerWithNotificationHubs();

    // completed Code
}

// Added Method
@SuppressWarnings("unchecked")
private void registerWithNotificationHubs() {
    new AsyncTask() {
        @Override
        protected Object doInBackground(Object... params) {
            try {
                String regid = gcm.register(SENDER_ID);

                Log.e("regid RECEIVED ", regid);
                hub.register(regid, "androidapp_" + WhatsOnIndiaConstant.USERId);

                WhatsOnIndiaConstant.notificationHub = hub;
                WhatsOnIndiaConstant.gcmHub = gcm;

            } catch (Exception ee) {
                Log.e("Exception ", ee.getMessage().toString());
                return ee;
            }
            return null;
        }
    }.execute(null, null, null);
}
like image 767
Jigar Joshi Avatar asked Mar 10 '15 15:03

Jigar Joshi


1 Answers

Every time a user uninstall & re-installs the app, a new token is returned. So, for that given tag, multiple registrations are made leading to duplicate pushes delivered to the same device.

As far as I understood, there is only one working device token at a time for Apple Push Notification Service (also see here), so you won't have a problem with multiple valid device tokens for one device under iOS, but you could have multiple Azure Notification Hub registrations for one device token. To avoid this, you have to check if there are already registrations for the concrete device token and if so, reuse and clean them up:

ASP.NET WebAPI-Backend example:

// POST api/register
// This creates a registration id
public async Task<string> Post(string handle = null)
{
    // make sure there are no existing registrations for this push handle (used for iOS and Android)
    string newRegistrationId = null;

    if (handle != null)
    {
        var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);

        foreach (RegistrationDescription registration in registrations)
        {
            if (newRegistrationId == null)
            {
                newRegistrationId = registration.RegistrationId;
            }
            else
            {
                await hub.DeleteRegistrationAsync(registration);
            }
        }
    }

    if (newRegistrationId == null) newRegistrationId = await hub.CreateRegistrationIdAsync();

    return newRegistrationId;
}

With Google Cloud Messaging, it seems you can have multiple working GCM registration IDs, so you have to take care of this. GCM has something called "Canonical IDs":

If a bug in the app triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.

GCM provides a facility called "canonical registration IDs" to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your app. This is the ID that the server should use when sending messages to the device.

If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the registration_id field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.

like image 112
Baris Akar Avatar answered Oct 18 '22 19:10

Baris Akar