Code Wanderlust

Upgrading Ionic.io Push Notifications Tips and Tricks

Introduction

Sam Brown

Sam Brown

Product Architect at a small startup and Organizer of DC Continuous Delivery. Passionate about clean code, automation and helping teams deliver great software!


Upgrading Ionic.io Push Notifications Tips and Tricks

Posted by Sam Brown on .
Featured

Upgrading Ionic.io Push Notifications Tips and Tricks

Posted by Sam Brown on .

Background

I've recently had the opportunity get deep into using the Ionic framework for an iPad app I'm building for my company's product. Ionic is a JavaScript framework built on top of Apache Cordova that helps web developers familiar with JavaScript to quickly create cross-platform mobile applications.

Ionic has built some awesome features that really smooth the use of cordova with enhanced command-line features as well as adding some default styling that make building a working cross-platform application much more accessible to the average web developers

Ionic.io

The team behind the Ionic Framework has also created a companion set of services designed to help smooth some troublesome spots in app development. Ionic.io provides light user management, push notifications, app-deployment and analytics in a single platform complete with a UI dashboard.

Push Notifications

I'm taking advantage of Ionic.io push notifications and last week I was finally able to get things working after a decent amount of trial-and-error (and blog reading). Unfortunately, the timing couldn't have been worse (or better depending on how you look at it) because a few days later the Ionic.io team released their new ionic-platform-web-client to help solidify their offering and remove dependence on AngularJS from their services. This move makes sense but this disrupted the way I had coded my app so I went back to the drawing board, and the docs, to update. Here are some things I found that I hope help others along the way.

Registering Users and Tokens

In the previous iteration of Ionic.io push the user could be created and or saved with their device token as soon as the device called the register function. Unfortunately this is now a 2 (or 3) step process due to the developers pulling the User and Push services apart. I don't think this will be as confusing to new users of the platform but for those doing it the old way, here is how I am doing it now:

  • In your $ionicPlatform.ready function you need to initialize both Ionic.io() and Ionic.Push(). Ionic.io() needs to be called first!
  • On user login I call to load the ionic user from the service:
function retrieveOrCreateUser(callBack){  
      var userId = $rootScope.currentUser.id; //Your unique user id
      Ionic.User.load(userId).then(function(user){
        logger.log('Loaded Ionic User: ' + JSON.stringify(user));
        Ionic.User.current(user); // Tell Ionic about user and set to local storage
        return callBack();
      }, function(error){
        logger.log('Error loading user from Ionic: ' + error);
          var newUser = Ionic.User.current(); // No user found at Ionic.io, create new
          newUser.id = $rootScope.currentUser.id; //Still set using your unique id
          newUser.save(); // Saves user to Ionic.io as new user, saves to local storage
          return callBack();
      });
  • Now that the user has been created or loaded, you can call for push registration in the callback or promise.
function registerPush() {  
      logger.log('Registering for push...');
      push.register(function(registration){ // register for push
        var user = Ionic.User.current();// Load current user
        push.addTokenToUser(user); // Add token to that user
        user.save(); // save user with token to Ionic.io
      });
    }

Ionic.io Settings in Non-standard Directory Structure

The below is probably only relevant if you are moving from the old Ionic.io angular services to their new namespace. If you are starting from scratch you will NOT encounter these issues.

An application using Ionic.io services needs to create a local settings file and have those values propagated to the file www/lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js. If you have a standard directory structure like what is listed then a simple ionic config build will propagate your values from .io-config.json into that file without any hassle. Unfortunately my directory structure is non-standard (from a yeoman generator) so here is what I did

  • Created a JS script that will go into the file and put the values from .io-config.json into the correct place in ionic.io.bundle.min.js:
#!/usr/bin/env node

/**
 * Update ionic config settings because project has non-standard directory structure.  This is normally
 * done by ionic config build command
 */
var fs = require('fs');

var CORE_FILE_MIN = './app/bower_components/ionic-platform-web-client/dist/ionic.io.bundle.min.js';  
var CONFIG_BACKUP = './.io-config.json';

var SETTINGS_REPLACE_START = "\\\"IONIC_SETTINGS_STRING_START\\\";";  
var SETTINGS_REPLACE_END = "\\\"IONIC_SETTINGS_STRING_END\\\"";  
var SETTINGS_REPLACEMENT = "return { get: function(setting) { if (settings[setting]) { return settings[setting]; } return null; } };";

function isCoreAvailable(callBack) {  
  fs.exists(CORE_FILE_MIN, function(exists) {
    if (exists) {
      return callBack(true);
    } else {
      return callBack(false);
    }
  });
}

isCoreAvailable(function(available){  
  console.log('Updating Ionic IO Config values...');
  if(available){
    fs.readFile(CONFIG_BACKUP, function(err, data) {
      if(err){
        return console.error('Could not read IO Config file .io-config.json. Did you create it?'.red);
      } else {
        var jsonConfig = JSON.parse(data);
        fs.readFile(CORE_FILE_MIN, function(er, content) {
          var jsMinFile = String(content);
          var replacementString = "var settings = " + JSON.stringify(jsonConfig) + "; " + SETTINGS_REPLACEMENT;
          jsMinFile = jsMinFile.replace(new RegExp('(' + SETTINGS_REPLACE_START + ')(.*?)(' + SETTINGS_REPLACE_END + ')', 'g'), '$1' + replacementString + '$3')
          if (jsMinFile) {
            fs.writeFile(CORE_FILE_MIN, jsMinFile, function(e){
              if (e) {
                return console.error('Could not write ' + CORE_FILE_MIN + ' due to: ' + JSON.stringify(e));
              }
              return console.log('Successfully added IOConfig properties to ' + CORE_FILE_MIN);
            });
          } else {
            return console.error('Unable to build the config factory'.red);
          }
        });
      }
    });
  }
});
  • Obviously update CORE_FILE_MIN to the location that matches your structure
  • I added this as a grunt-exec in my build process as well as a hook for afterplatformadd in Ionic
  • Most of this code is from the Ionic team's CLI so you can be fairly certain it works correctly.

NOTE If you use this code you MUST check in your .io-config.json file so that this script can get the values.

Testing with dev_push=true

After upgrading I also could not get dev pushes sent to my browser but it had been working previously. After tracing through the ionic code I discovered that the services will load cordova.js on their own now. Unfortunately I had it loaded by my index.html file so this was causing cordova to double load and took a different branch of logic in loading the push services for Ionic.io. You can avoid this by commenting out the following in your index.html:

<!-- <script src="cordova.js"></script>  -->  

Once you've done this, if you run your app in the browser with dev_push=true in your .io-config.json file then you should receive proper notifications when using the DEV tokens you get back from registration.

Other Notes

The Ionic.io documentation is a bit tough to find your way through but most of the items are documented fairly well and there is a gitter channel where the developers are available to help with any problems or questions. Overall I have had a really good experience with Ionic and I look forward to the great things they will come up with next.

Sam Brown

Sam Brown

Product Architect at a small startup and Organizer of DC Continuous Delivery. Passionate about clean code, automation and helping teams deliver great software!

View Comments...