Push Notifications in Android App


#1

Hello All, Can some one provide some input on how to implement push notification through ionic/phonegap.

Scenario, is just like how outlook/calendar work.

I am having a rest service when it sends some notifications. When ever this service sends message my app has to catch it (even in idle state)and should display as notification to user.

Can some one share implementation details on this? Mainly, Like how angular should listen to any messages from server…how to do notifications to user. I know i have to user phonegap notification API. BUt, I am looking more on how my app should catch data from server on Active/idle state.

Thanks.


Pushwoosh integration with ionic
#2

Adding push notifications is a bit more complex than just a simple post. First you should check out some angular wrappers for push notifications.

If you plan to host the server yourself, then best of luck to you :smile:

But if you able to use a service, I’d suggest pushwoosh. They are simple to set up, works with cordova, and provide an in-depth guide for iOS and android.


#3

Hey, Thanks for quick reply.
I will look in to pushwoosh - Seems its just a service and it free for sending messages.

Do you thin i can use Android Cloud to Device Messaging Framework?


#4

Nope, as it is depreciated and no longer accepting users or new accounts. You nee to you GCM

http://developer.android.com/google/gcm/index.html


#5

Thank You. I implemented with GCM and https://github.com/PatrickHeneise/angular-phonegap-push-notification successfully.

One question though, I opened app and I placed a “Register” button in my App. On click of this button I am registering device for push notifications. After that I am push notifications from server and I am able to receive successfully. But, lets say I clicked on “Home” button of device. I navigated different app and came back to my push notification app again. (now, my app is in running state) Now, if I send message from server I am not seeing notification. But If I click on register button then I am receiving message. Is this correct approach? Every time I open app I need to register device?


#6

If it’s taken right from the example, no, that’s just meant to show you an example of the API. A better example would be to just register the device for notifications on load, or present a popup to let them chose to show notifications ( think iOS)


#7

@mhartington how would you respond to resume states in iOS?

My problem is this, I’m setting local notifications using this plugin: https://github.com/katzer/cordova-plugin-local-notifications

When I close the app, it enters the ‘suspend’ state in iOS.

Then, when the notification appears, tapping it will load the app again, resuming the previous state prior to suspension. I need to navigate to different view when the app is loaded from a notification. How is that done? I’ve been completely stuck on this all day!

Any help is greatly appreciated, I’ll buy you a case of beer if you help me!


#8

Can’t say for that plugin, but for cordova’s official plugin,
http://plugins.cordova.io/#/package/org.apache.cordova.dialogs

You would do something like this.

function alertDismissed() {
     $state.go("whereever.we.needTo.go")
}

navigator.notification.alert(
    'You are the winner!',  // message
    alertDismissed,         // callback
    'Game Over',            // title
    'Done'                  // buttonName
);

Plus this has the benefits of having a ng-cordova wrapper already made for it.


#9

This is more like a notification when the app is minimized on iOS. I’m not so sure it is possible now without using push notifications. However, our client doesn’t want to support / pay for push notifications so I’m not sure how to proceed with this. Local notifications are not flexible at all.


#10

The only problem with this implementation is my onNotificationAPN function is “outside of angular.” So $state is not present. I guess I could just do window.location(fullURL)?


#11

Note: You can attach the onNotificationAPN function to your angular application variable - then you are inside angular and should be fine.

var app = angular.module(‘app’, [‘ionic’, ‘ngSanitize’, …
then after ionic.Platform.ready(function(){… you register for push and use
app.onNotificationAPN = function onNotificationAPN (event) { etc…


#12

@darrenahunter I don’t quite understand. Can you put in a code example? This is not really clear.

Thanks!

here is my SO question:


#13

If I get a chance tomorrow I will add some code.

Basically where you define your onNotificationAPN function - add it to whatever variable you defined for your angular application.
mine is ‘app’ as in var app = angular.module(‘app’, [ionic…


#14

I use the Aerogear Unified Push Server. I also use a “PushNotifications” factory to register, unregister and notification handler.


#15

I also use a PushNotification factory, but how do you “call in” to angular?

pushNotification.register(successHandler, errorHandler,
     { "senderID":"SENDERID",
       "ecb":"onNotificationGCM" });

That onNotificationGCM function is outside of my angular app. Its just an anonymous function


#16

I just have the “onNotificationGCM” function defined as a private function on the factory. In my case, the register function is passed the function that needs to be called. In your case, you might be able to put “pushNotification.onNotificationGCM” as the function name.

onNotificationGCM = function(data) {
// do something with data…
};


#17

Hey @ajbraus, this is a common question in Angular and it’s very doable to talk between non-Angular and Angular.

Here are some options:

Use the injector

You can access the injector for your module outside of angular. All you need is a reference to the root element of the ngApp:

var pushNotification = angular.element('html').injector().get('pushNotification');
// pushNotification now contains a reference to this service.

Or, you can bind to the register function inside of an angular context through a closure:

// In the controller:
controller('MyCtrl', function($scope, pushNotification) {
  pushNotifcation.register(function() {
    // Access to scope
  });
});

That help?


#18

Sorry I’m dense!

What I have works, I just can’t reference $state and $scope the way I want to.

So in app.js outside of my main angular.module(‘starter’ . . . ) method I put this private function (for iOS notifications):

function onNotificationAPN(event) {
  console.log('APN Notification received');
  console.log(event);

  if ( event.alert ) {
    navigator.notification.alert(event.alert);
  }

  if ( event.sound ) {
    var snd = new Media(event.sound);
    snd.play();
  }

  if (event.custom.url) {
    window.location.assign(event.custom.url);
  }
}

In my PushNotification Service I have a register function that references this function to run it when a push notification comes through.

  .factory('PushNotification', function ($ionicPlatform, Device) {
    function successHandler (result) {
      // alert('result = ' + result);
    }

    function tokenHandler (result) {
      // alert('result = ' + result);
      var device_data = {
        token: result,
        platform: ionic.Platform.device().platform
      }

      localStorage.setItem('device', JSON.stringify(device_data));
      Device.save({}, device_data, function(data) {
        console.log("Saved device.");
        localStorage.setItem('device', JSON.stringify(data));
      });
    }

    function errorHandler (error) {
      alert('There was a problem registering your device for notifications: ' + error);
    }

    return {
      register: function() {
        var platform = ionic.Platform.device().platform
        if (platform != null) {
          var pushNotification = window.plugins.pushNotification;
          if ( platform == 'android' || platform == 'Android' ) { //|| platform == "amazon-fireos"
            pushNotification.register(successHandler, errorHandler,
              {
                "senderID":"GCM SENDER ID",
                "ecb":"onNotificationGCM"
              });
          } else {
            pushNotification.register(tokenHandler, errorHandler,
              {
                "badge":"true",
                "sound":"true",
                "alert":"true",
                "ecb":"onNotificationAPN"
              });
          }
        }
      }

I don’t see exactly how I can put the onNotificationAPN function into the angular context?


#19

is there a difference between:

angular.element(document.querySelector('[ng-app]')).injector().get('PushNotification');

and

angular.element('html').injector().get('PushNotification');

the first one works in the console. The second one gives this error:

Error: [jqLite:nosel] Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element http://errors.angularjs.org/1.2.17/jqLite/nosel


#20

Hey, it depends where you’ve defined ngApp. I’d say just use root element: $rootElement.injector().

As for the function thing. This is strange. You are passing a string, so it’s probably doing an eval or something. If you can pass in a function object then you can control the calling context.

At any rate, using the injector will make it work regardless. Try in your onNotificationAPN function:

var element = document.querySelector('.ng-scope');
var $rootElement = angular.element(element).injector().get('$rootElement');

Then get any service from that.