Search

Building high performance hybrid mobile clients for the IoT world with Ionic

September 21, 2015


With the proliferation of IoT devices in the market the the recent surge of DIY as well as cloud based "plug and play" home security solutions such as those from Dropcam, Simplicam, D-Link (and the resurgence of DIY solutions using Motion or ZoneMinder), many solution providers are looking at powerful mobile clients to monitor as well as control their home appliances, be it cameras or home lights as well as be notified of motion detection activities while away. This article will discuss how one can (and should) leverage modern hybrid frameworks such as Ionic, Meteor or similar solutions to develop a common code base that works across multiple platforms and yet not compromise on speed or performance. Specifically, this article will focus on Ionic, a very powerful MIT licensed framework based on AngularJS that sits on top of cordova and bring out the advantages of such a solution.

IoT application requirements

One of the first things that one should assess is what a typical IoT application requires and then assess whether a hybrid framework is the right approach or a full native solution. The following key traits likely apply to most IoT mobile clients:

  • Most IoT clients will need to interact with RESTful APIs, either over HTTP or HTTPS
  • Ability to manage large lists and scroll without performance issues (example, if you have 20 cameras installed in an industrial building, you can imagine how many events can be generated in a matter of hours)
  • Ability to display video feeds via H.264 or MJPEG or JPEG and access the camera
  • Support for push notifications
  • Ability to interact with accessories over WiFi/BT/BTLE
  • Leverage native plugins where needed (example Address Book)
  • Use wither IPv4 or IPv6 as applicable
  • Support WebSockets (ws/wss)
  • Easy to use professional UI elements that don't require developers to create UI elements from scratch using HTML5
  • Support multiple forms of authentication and authorization (oAuth, TouchID, etc.)
  • Support for graphing & visualization tools (IoT is all about data respresentation and eye-candy for the app side of things)

While there are many other requirements, the list above is pretty much the core/important needs. IoT apps are almost always CRUD sort of applications - they are almost always interacting with some API, getting/setting/retrieving and rendering values at its core. This is unlike, say, a gaming application where the core requirements are high speed graphics rendering/scaling (incidentally, don't knock hybrid apps for gamers too - check out Phaser IO, a great example of how far web engines have come - fully hardware acclerated 3D transformations built right into your browser)

Why Ionic?

Ionic is MIT licensed. So is Angular JS and so are the many, many plugins for both

Simply put this means the following:

  • It's free to use
  • It's free to deploy for commercial purposes without any obligations to share modified code

Ionic combines AngularJS with Cordova - programming just got much easier

AngularJS is often referred to as "the super-heroic JavaScript MVW framework". The 'W' stands for 'Whatever'. Many people develop Angular using the standard MVC model, but Angular offers other models that may suit your programming needs. This post by one of the Angular authors summarizes this aptly.

Cordova has many plugins for native platform integration. Over the years, developers have added key platform specific plugins to cordova which are all available to ionic. But on top of that, ionic folks regular keep updating ngCordova which is the Angular-ized version of many of these plugins. You can use either version - using the ngCordova version makes it much simpler to use than the standard Cordova Javascript based invocation. Here is a simple example of how one may use touchID but only if the platform is iOS using ionic: - This example uses $cordovaTouchId (here).

if ( $ionicPlatform.is('ios'))
        {
            $cordovaTouchID.checkSupport()
                .then(function () {
            // success, TouchID supported
                $cordovaTouchID.authenticate("")
                    .then(function() {
                        console.log("Touch Success");
                        // Do unlock code here

                    }, 
                    function () {
                       console.log("Touch Failed");
                });
            }, function (error) {
                console.log("TouchID not supported");
            });
        }
        else
        {
            console.log("Not iOS, not checking for touchID");
        }

That's it. With just a few lines, you've integrated touch-ID into your app. Obviously, touchID is a platform specific API only available on iOS which also tells you that it is pretty straight forward to integrate platform specific code into your code and ionic gives you all the platform check APIs needed to invoke code specific to a platform ($ionicPlatform.is is how we are checking). If you are concerned that there will be too much fragmentation, don't worry, most of the angular plugins for cordova work on both android and iOS (and often Windows too), as long as what you need is not a feature that is closely tied to a specific platform. For example, the ngCordova $cordovaContacts plugin abstracts address book entries for all platforms - you don't need to worry about how to handle them differently.

Angular is ideal for apps that are data centric

IoT apps are almost always data-centric. They are always fetching/displaying/rendering and processing fast changing data (the data could be from sensors, cameras, or any thing else). A great propery of Angular is its very powerful data binding approach. The 'view' part of Angular, which is defined by HTML pages called 'templates' can use "angular expressions" and "angular variables" which create a binding between the model and its representation and Angular takes care of updating the value as it changes. Consider for example, a situation where you are retrieving a sensor value via an API and you need to display it in a view. Obviously, it is a bad idea to 'freeze' the app while you wait for data. You'd much rather keep rendering views as fast as possible for the app to be responsive and update the data when it is ready. So here is an example of how easy that is to do in AngularJS (and therefore ionic that is written on top of Angular)

This is the template code: (Note the angular variable sensorVal - its in double curly braces which means Angular will evaluate its value every cycle - called a digest cycle)

Sensor Value: {{sensorVal}}

And this could be the corresponding controller code for that view:

$scope.sensorVal="loading...";
$http.get("http://mysensorcloud.com/api/getHeartRate.json")
.then ( function (success) {
$scope.sensorVal = success.data;
},
function (error) {
$scope.sensorVal = "error retrieving data: " + error.reason;
});

This is an example of using promises to handle deferred responses. The HTTP query can take time, but Angular knows that "sensorVal" is bound to the template view, so anytime sensorVal changes, the view gets updated (assuming you are in that view)

Ionic is very high performance

This is probably a favorite complaining point for many. Many believe programs written using an HTML5 canvas (WebView) is not fast enough. One activity that is regularly complained about is scrolling performance. The premise of the argument is that as the list increases, a webview is simply not geared to handle large list scrolling. Well, good news when it comes to ionic:

  • Ionic integrates both javascript scrolling and native platform scrolling into its library. So when you are implementing large lists, you are actually scrolling at native speeds. There is really no difference at all in performance. We've used ionic to scroll over 8,000 items with absolutely no performance degradation
  • Native platforms have a concept call 'cell reuse' where the UI is rendered only for the view that is in visible area. Traditionally, webviews renderered everything, event those that did noy present themselves in view. Well ,no more: ionic offers the 'collection-repeat' directive that provides exactly the same thing greatly improving performance
  • Are you concerned about webview's 300ms delay for gesture recognition? Don't be. These are problems of the past. Ionic supports many gestures as well as you'd like, like touch, swipe, double-touch, pinch and zoom and more (and if you have any missing, like maybe pinch-and-rotate, write your own directive)

Caveat:Specific for Android users, those who have tried using ionic and have faced performance issues are likely using versions of Android prior to 4.4. The problem here is that older versions of Android packaged a low performance webView and not chrome as the default webview. To work around this aspect, the cross-walk project was launched and ionic quickly adopted this too. Simply put, you can combine crosswalk into an ionic project and have it render within a chrome view which offers excellent performance. Note that this does increase your APK size by around 15-20MB. If that is a problem for you (is it really?) then you can look at crosswalk-lite that weights in at 10MB.

Code re-use is easy

This is not really an Ionic feature but an Angular feature. One key compliant from many is it is hard to write re-usable code with well defined libraries when doing hybrid apps. This is simply not true. Angular has the following key code-reuse and organizational structures that we highly recommend you use:

  • Directives: Directives are a very powerful tool when you need to constantly deploy code that requires UI interactions. Simply put, let's suppose that you want to implement a "pullup" window that is present in multiple application views. The design goal is this: In various views, you want a small pull up handle at the bottom that sits inconspicuously at the bottom. When you pull it up, it displays some content. While the content can change per page, the construct, gesture interaction and UI presentation remains the same. You _could_ write this as a standard javascript library and invoke it in JS code, writing code to inject itself into the correct HTML segment. But there is a better way, write is as a directive. A 'directive' allows you to create your own DOM element that you can re-use in any part of your code. For example, you can define an <ionic-pullup-bar> right inside your HTML template code and "inject" the directive code into the controller for your view and then all the logic of that code sits pretty inside the directive code. Take a look here for an example on how this works. This is an example of a hardware accelerated CSS usage (it uses transform3D) and you can see the performance for yourself.
  • Factories and Services: When you don't need to manipulate or access DOM elements/gestures, you can use Factories and Services. Simply put they are great for backend re-usable code elements. they act like Singletons and can be invoked by any controller. They can also be used to share data between controllers if you are wondering. How do you use them? Well, lets first talk about the next point:
  • Dependency Injections: AngularJS allows you to 'inject' dependencies into any controller code. For example, lets suppose you write a great singleton called 'ServiceLogin' that logs into your backend server every 3 hours and refreshes tokens. It's got a method called ServiceLogin.login() that does this job. to call it from any module, all you really need to do is add 'ServiceLogin' as a dependency when you declare the controller that needs it like so:
someModule.controller('MyController', ['$scope', 'ServiceLogin',  function($scope, 'ServiceLogin') {
  ...
  ServiceLogin.doLogin();
    ...
  }
  ...
}]);
  • So to answer the previous question on sharing data, imagine two controllers sharing a common factory with a "set" function that changes data and a "get" function that gets that data. We have data sharing, don't we?

Professional UI components

This should really be at the top of the list. The bane of any application is asking an engineer with no UX experience to develop a screen. You will inevitably have a bright green button with a blue underlined hyperlink somewhere down the line, or, with the more experienced, views that suddently truncate when switched from landscape to portait. This was a little tongue-in-cheek but you've faced this problem, haven't you? We've seen, literally, hundreds of cordova/phonegap applications with really bad UI screens. And here is why: Designing HTML5 UI's is HARD. Different browsers have different ways of handling CSS. Even if you did know CSS, selecting the right UI colors, width, screens etc is not easy. Here is where ionic really shines:

  • Take a look at ionic components here - they have wrappers for most basic UI elements - from lists, to input fields, to radio buttons to grids. All you really need to use is use the right ionic directive. Ah, there you go - directive. Ionic has defined many directives that start with "ion-" - these are wrappers around HTML5 DOM elements that apply specific styling. Take for example <ion-range> which wraps around the HTML5 range DOM element and gives it a polish you really need. Specifically, it is hard to make a horrid UI with ionic unless you really try.
  • Ionic has many starter templates that make it easy for you to write your app. Would you like to implement a side scrolling menu? here is a directive for that, or, just start with one of their many starter templates here
  • Ionic comes with a large set of SVG icons, again MIT licensed for re-use in your apps. And of course, it is trival to include fontawesome into your apps as well. All you need to do is to add "<llink rel="stylesheet" href="lib/font-awesome/css/font-awesome.min.css">" to your CSS and go ahead and use the fa classes.
  • Ionic is fully SASS compatible - which means you can easily manage multiple themes and skins for your app without any change to any file except for the "scss" file.

Camera, Image/Video support

Let's make sure we cover all the IoT requriements we wrote about earlier. HTML5 (and therefore Ionic) supports a <video> tag that plays H264. And obviously the <img> tag for images, even progressive images that change every few seconds (this is how old motion capture systems work - they establish a long term HTTP connection that keeps streaming JPEGs over multipart/mime over a single TCP connection) And as far as camera goes, we have cordovaCamera And while we are at it, discussing plugins, nothing stops you from writing your own plugin. You'd do that in 3 steps:

  • Write your own native code library
  • Write the cordova wrapper for that library - example here
  • If you want write an angular wrapper for this to make it even better (take a look at the wrappers for any of the plugins at ngCordova)

Support for HTTP/HTTPS/WebSockets

Multiple protocols are easily supported, even HTTPS. Note that if you are using a self signed certificate for HTTPS you need to make sure the certificate is installed on the phone as well. For websockets, there is this plugin that makes it very simple Here is an example of how an http request looks like in Angular/ionic:

var myurl="https://myserver.com/api/v3/getSubscribers.json";
$http.get(myurl)
.then( 
	function(succes)
	{
	},
	function(error)
	{
	});

That's it. Incidentally, this also introduces us to a very powerful (and confusing, if you don't understand it) construct called 'promises' that make it very simple to handle asynchronous operations very easy. For example: let's suppose you make an HTTP query and it takes 10 seconds for the server to respond. By that time you have navigated away to some other screen. What happens to the response? Promises stick around to handle the response easily in that code block.

Push Notifications

Ionic fully supports push notifications. It actually supports two versions:

  • Push notifications via native platforms like APNS/GCM via cordovaPush
  • Access to ionic's own websockets based push notifications (read more here)

Support for multiple auth schemes

There is nothing here that is specific to angular or ionic, but there are many libraries out there to get you started For example $cordovaOauth for logging in via many oauth services like Facebook, Google+, etc.

Huge ecosystem of MIT licensed libraries

There are literally several hundred of supported libraries for many things you want to achieve and most of them are MIT licensed (commercial software friendly). Before you go about writing your own, look at the following places:

Incredible graphing and visualization tools

There are really, incredible tools out there for graphing and visualization. Some of our favorites:

Here is an example of using chartist for impressive graphs animated in real time

See the Pen Responsive Charts with Chartist.js by Gion Kunz (@gionkunz) on CodePen.

 

Good debugging tools

Surprised? Aren't javascript apps a nightmare to debug? Generally yes, but here are some incredible things developers should leverage:

  • Ionic allows you to render your app on your desktop for testing - see "ionic serve"
  • Ionic allows you to render both iOS and Android UI screens next to each other to compare. See "ionic lab"
  • The absolute best tool for debugging JS and Angular apps is Chrome. While safari too has a built in inspector that can remotely connect to web apps on a device, Chrome takes it to a new level, allowing you to attach breakpoints and inspect and change code live. It is incredible and no developer should be without it. Read more about remote debugging here
  • Batarang is an excellent debugger for Angular apps - specifically undestanding what is in $scope and what is not and other benefits. Note that Batarang may not work with Angular 1.4x as of today.
  • Use CodePen, Plnkr or JSFiddle when asking for tips -- these platforms allow others to run code right within the browser and then fork and offer suggestions on how to fix problems - how amazing is that? You read/code/fix/run/share code within the same browser
  • As a live example, embedded right into this page is the code as well as the result of the code of a radial menu that you can view/edit/hack right here (tap on the menu icon below):

    See the Pen Animated radial / circular menu by Creative Punch (@CreativePunch) on CodePen.

Caveats

Just like surfers are always reminded to respect the waves, no matter how good they are, we like saying 'respect the DOM'. As simple as AngularJS and Ionic looks, writing a good app needs sound design principles when you go beyond writing the simplest of apps. These days ionic (and similar frameworks) are being used to write very intensive apps like chat clients to video calling clients to full featured IoT mobile apps and there are many things to watch out for. Some items worth remembering:

  • Respect the DOM. Don't add too many watchers and scope modifiers. The more you add, the slower it will get (but really, we are talking about in the 1000s)
  • Spend time reading how Angular works, what a digest loop means and what scope means. Its non-trivial and a lack of understanding of how angular manages context will result in you spending many hours of wasted debugging
  • Respect console errors and logs. Always keep them on when testing code - things like injection errors, or 'module not found' occur before your app UI can really load up and the only way to find them out is to monitor the console
  • Use good design practices. Don't start using $rootScope everytime you want to share data between controllers. Seperate functionality into Directives, factories/services/providiers depending on need and use dependency injection to maintain reusable code
  • Get a good understanding of a view lifecycle - so you know what happens when your app transitions screens, resumes, terminates etc. You have handlers for each of these situations that you should use to clean/clear/update/release data as needed
  • Use grunt/yeoman and other scaffolding tools to make your build process automated
  • Uglify/minify your code before publishing
  • Declare your dependencies using the array notation - if not, when you minify/uglify some of your dependencies may get left out and your app won't work
  • If you are using Android make sure you read about whitelists and content-security - otherwise you'll find HTTP requests don't work on your device
  • Use chrome debugger and batarang extensively - they will boost your productivity while debugging. At the same time, don't underestimate the power of a simple console.log
  • When publishing apps, using ionic hooks and grunt based scaffolding to automate your tasks (one of many examples here)

Conclusion

Hybrid apps have come a long way. The offer native like performance with the benefits of code-reuse across platforms. Before you consider going the native way, consider if your team knows enough about hybrid apps. Have them explore Ionic (the focus of this post), or alternate tools like Meteor If you are considering cordova (phonegap), we strongly recommend you don't stop at just phonegap/cordova. Use a platform like Ionic on top of it, bring in the power of AngularJS and watch your apps get a new life.






2 Comments


  • Oct 21, 2015
    Marc
    Have you actually gotten D3 to work with Ionic? Having trouble getting anything to render properly, myself.

    Reply
    • Oct 29, 2015
      HSC Admin
      Hi Marc, yes. I used angular-nvd3 and got it working. It's extremely powerful too, but if one's needs are simpler, I think chartist (moderate simplicity) and chartjs (very simple) are easier alternatives.

      Reply


Add Comment