Using Ionic with Amazon SNS for Push Notifications for iOS and Android?

Hello,

I’m new to Ionic (started 3 days ago) and am currently using it to build out a mobile app for my site at http://huat.sg. I’ve made good progress with AngularJS, Ionic and all, and I believe the app is ready for release, with the exception of push notifications.

Can someone point me in the right direction, specifically if I’d like to use Amazon SNS?

Thank you!

I’m using pushwoosh which has been a breeze to implement. Has a phonegap api.

I’ve taken a look at PushWoosh but I’m a little lost at how to integrate it into Ionic/AngularJS, any pointers on this? Thanks!

I use Parse however it is a little difficult to implement but once done has been very strong - big plus ‘it is free’ (well up to a million per month I think)

darrenahunter: I’ve checked it out as well, I thought their JS SDK didn’t support Push? Great work on implementing it :)!

I’ve went ahead with Amazon SNS (PushWoosh has no API support for the Free package, I need API support), and have gotten it to work with Android so far. I’ll try to write about it in detail once I’ve the iOS part working as well!

1 Like

@Wysie glad you got it going

Parse JS SDK does support push (ios little easier that android - but still ok)

following is my push service for reference just incase it can help

I then have a Admin Dashboard Website that the client uses to send pushes to the app users. This uses the JS SDK also to send the pushes

cheers

.factory('push', function (CommonService, LogService, $http, $ionicPopup) {
    return {
      registerPush: function (tester) {

        LogService.add('Push Register as Tester: ' + tester);

        var pushNotification;
        pushNotification = window.plugins.pushNotification;

        // result contains any message sent from the plugin call
        var successHandler = function successHandler (result) {
            //alert('Success Handler Result = ' + result);
        };

        // result contains any error description text returned from the plugin call
        var errorHandler = function errorHandler (error) {
            //alert('Error Handler Error = ' + error);
        };

        var tokenHandler = function tokenHandler (result) {
            // Your iOS push server needs to know the token before it can push to this device
            // here is where you might want to send it the token for later use.

            // Rest call to Parse to Insert/Update the Installation record for this Device
            $http({
                url: "https://api.parse.com/1/installations",
                method: "POST",
                data: {"deviceType": "ios",
                       "deviceToken": result,
                       "testdevice": tester,
                       "channels": [""] },
                headers:  {"X-Parse-Application-Id": CommonService.parse_appkey,
                           "X-Parse-REST-API-Key": CommonService.parse_restkey,
                           "Content-Type": "application/json"}
            }).success(function (data, status, headers, config) {
                LogService.add("iOS Token: " + result);
                    //alert('iOS registered success = ' + data + ' Status ' + status); 
                }).error(function (data, status, headers, config) {
                    //alert('iOS register failure = ' + data + ' Status ' + status);
                });
        };

        // iOS
        onNotificationAPN = function onNotificationAPN (event) {
            LogService.add('onNotificationAPN Triggered');
            if ( event.alert ) {
                // Note: Popup done differently to gcm but this works for ios
                var myPopup = $ionicPopup.alert({
                 title: CommonService.Title,
                 template: event.alert
                });
                myPopup.then(function(res) {
                  console.log('iOS Message: ' + event.alert);
                });
                LogService.add("iOS Msg Received. Msg: " + event.alert);
                //navigator.notification.alert(event.alert);
            }
            if ( event.sound ){
                var snd = new Media(event.sound);
                snd.play();
            }
            if ( event.badge ) {
                pushNotification.setApplicationIconBadgeNumber(successHandler, errorHandler, event.badge);
            }
        }

        // Android
        onNotificationGCM = function onNotificationGCM(e) {
            LogService.add('onNotificationGCM Triggered: ' + e.event);
            //alert('GCM event = ' + e.event);

            //TODO : Fix up registering GCM devices and having duplicate gcmRegId's on Installation class if user
            //       reinstalls app as it will get a new unique InstallationId and therefore write new record.
            //       Even don't attempt to write/update the record if the installationid and gcmregid haven't changed
            //       this would require saving them to localstorage to check - InstallationId is already saved to
            //       localstorage by parse sdk.

            switch( e.event )
            {
            case 'registered':
                if ( e.regid.length > 0 )
                {
                    //alert('GCM registered event regid = ' + e.regid);
                    //alert('Parse InstallationId = ' + CommonService.parseInstallationId);
                    // Rest call to Parse to Insert/Update the Installation record for this Device
                    $http({
                        url: "https://api.parse.com/1/installations",
                        method: "POST",
                        data: {"deviceType": "android",
                               "installationId": CommonService.parseInstallationId,
                               "gcmRegId": e.regid,
                               "testdevice": tester,
                               "channels": [""] },
                        headers:  {"X-Parse-Application-Id": CommonService.parse_appkey,
                                   "X-Parse-REST-API-Key": CommonService.parse_restkey,
                                   "Content-Type": "application/json"}
                    }).success(function (data, status, headers, config) {
                        LogService.add("GCM RegID: " + e.regid);
                        LogService.add("GCM Parse InstallationID: " + CommonService.parseInstallationId);
                            //alert('GCM registered success = ' + data + ' Status ' + status); 
                    }).error(function (data, status, headers, config) {
                            //alert('GCM registered failure = ' + data + ' Status ' + status); 
                    });
                }
            break;

            case 'message':
                // if this flag is set, this notification happened while we were in the foreground.
                // you might want to play a sound to get the user's attention, throw up a dialog, etc.
                if ( e.foreground ) {
                    $ionicPopup.alert({
                     title: CommonService.Title,
                     template: e.payload.message
                    }).then(function(res) {
                      //console.log('GCM inline notification event' + e.payload.message);
                    });
                    LogService.add("GCM Foreground Msg Received. Msg: " + e.payload.message);
                    //navigator.notification.alert(e.payload.message);
                    //alert('GCM inline notification event' + e.payload.message);

                    // if the notification contains a soundname, play it.
                    //var my_media = new Media("/android_asset/www/"+e.soundname);
                    //my_media.play();
                }
                else {  // launched because the user touched a notification in the notification tray.
                    if ( e.coldstart ) {
                        $ionicPopup.alert({
                         title: CommonService.Title,
                         template: e.payload.message
                        }).then(function(res) {
                          //console.log('GCM coldstart notification event' + e.payload.message);
                        });
                        LogService.add("GCM Coldstart Msg Received. Msg: " + e.payload.message);
                        //navigator.notification.alert(e.payload.message);
                        //alert('GCM coldstart notification event' + e.payload.message);
                    }
                    else {
                        $ionicPopup.alert({
                         title: CommonService.Title,
                         template: e.payload.message
                        }).then(function(res) {
                          //console.log('GCM background notification event' + e.payload.message);
                        });
                        LogService.add("GCM Background Msg Received. Msg: " + e.payload.message);
                        //navigator.notification.alert(e.payload.message);
                        //alert('GCM background notification event' + e.payload.message);
                    }
                }
                //LogService.add("GCM Msg Count: " + e.payload.msgcnt);
                //alert('GCM message = ' + e.payload.message);    
                //alert('GCM msgcnt = ' + e.payload.msgcnt);    
            break;

            case 'error':
                LogService.add("GCM Error: " + e.msg);
                //alert('GCM error = ' + e.msg);
            break;

            default:
                LogService.add("GCM unknown event");
                //alert('GCM unknown event');
            break;
          }
        }

        // Do PushPlugin Register here
        if ( device.platform == 'android' || device.platform == 'Android' )
        {
            LogService.add("Push GCM Register Sent");
            pushNotification.register(
                successHandler,
                errorHandler, {
                    "senderID": CommonService.gcmpush_senderid,
                    "ecb":"onNotificationGCM"
                });
        }
        else
        {
            LogService.add("Push iOS Register Sent");
            pushNotification.register(
                tokenHandler,
                errorHandler, {
                    "badge":"true",
                    "sound":"true",
                    "alert":"true",
                    "ecb":"onNotificationAPN"
                });
        };
      }
    };
  })
3 Likes

Thanks for sharing this! Very useful and I’ll keep this in case I’d need it for my future projects.

By the way, I’ve written how I made Amazon SNS work with Ionic for Android here: http://t.yc.sg/post/102663623041/amazon-sns-with-ionic-framework-part-1-android

3 Likes

How you get installationId? Do you use any plugin?
Sorry for de question I am new here.

Hi

The Parse SDK has an undocumented function to retrieve an installationId

CommonService.parseInstallationId = Parse._getInstallationId();
1 Like

I’ve used SNS with Ionic to send pushes, it’s not easy to setup but it’s way cheaper than other services. I basically used their javascript SDK in the app to communicate with SNS.

1 Like

I wrote a blog post on SNS with Ionic for Android here, hope it helps: http://t.yc.sg/post/102663623041/amazon-sns-with-ionic-framework-part-1-android

Hey @Wysie, thanks for the great post! Your example with the “msgcnt” parameter saved me some headaches :smile:

I have a question though. When I send a sample notification to my Android device from the Amazon SNS console I’m able to add the “msgcnt” parameter as you’ve shown and get the notification to pop up even when my app is in the background.

However, when I’m trying to send a notification from code, my notification is only delivered if my app is in the foreground. This is the string I’m sending in the “Message” parameter, and I’ve set “MessageStructure” to “json”.

{"GCM":"{\"data\":{\"message\":\"test\", \"msgcnt\": 2}}"}

Hello @mikeacook, thanks! Glad that it helped you :smile: Regarding your question, I am not sure without seeing your code on the app side. One question though, although it appears in the foreground, is it handled the same way as when you send it via Amazon SNS? Also, what language are you using?

Lastly, I figured out recently that the notification is not handled the right way (it always appears as a background notification even if I have the app open, and it doesn’t react the way I want to) if I don’t register the app on launch. I haven’t managed to find out why yet, but you could try setting var shouldRegister = true (instead of false) in my example code.

Hope this helps!

I got it working yesterday afternoon, it seems I was stuffing the JSON blob above into the parameter of:

{"default": "<-- here -->"}

Rather than sending it as the root level blob… (facepalm)

Hahaha @mikeacook, I’m sure I made similar mistakes before. Glad you got it all sorted out :)!

I just finished getting it to work with APNS (I think), need to test it somemore, and hopefully find time to write another post.

1 Like

I followed your example and I was finally able to register my phone on Parse, however when I sent a push notification from the Parse dashboard I did not receive it. Although, if I send it from the nodejs console it works like a charm. Is there something I am missing?

Never mind guys, as it seems if I supply Parse with my GCM project number and GCM API Key, they will stop using their own project number and API Key and use mine and that will work.

it’s a 50$ a month “breeze”. For free they will allow you only the dumb broadcasting.