Discover how we built our app in 2 weeks using Ionic Framework

  • 11 Nov, 2014
  • Ray Viljoen
  • 14 Comments

Discover how we built our app in 2 weeks using Ionic Framework

Airport Parking Shop is an established online comparison website that’s just celebrated its 11th year. Over the past few years we have watched as mobile (and tablet) usage has soared from just 8% of our traffic in October 2011 to 44% in October 2014. We couldn’t ignore this trend and so earlier this year we took the plunge and completely rebuilt our site with a mobile friendly responsive design.

Despite now having a very functional and mobile optimised site, with mobile use set to exceed 50% in the next few months, the next logical step was to offer our mobile users a more native experience so we decided build a dedicated app for both Android and iOS.

Having built both PhoneGap, Java (Android) and Objective-C (iOS) apps in the past, we were quite aware of the pros and cons, which in our opinion can be summarised as follows:

ProsCons
PhoneGap
  • Multi Platform
  • Web technologies (CSS, HTML, JS) which most developers know well enough.
  • Slow and unresponsive compared to fully native apps
  • Many device specific bugs
  • Complicated builds, releases etc. (Referring to icons, splash screens, certificates etc.)
Android Java Eclipse
  • Very fast
  • Native look and feel from standard UI components in the SDK
  • Single platform
  • Requires developer with Java skills
  • Using Eclipse (although some might love this)
  • Just about everything else the SDK has (or mostly doesn't have) to offer
iOS Objective-C Xcode
  • Very fast
  • Amazing visual UI editor and other development tools
  • Easy testing, building and release
  • Mac only
  • Single platform
  • Requires developer with Objective-C skills

Why Ionic

Having looked at all these factors, we did some research and stumbled across Ionic.

Ionic is a relatively new framework for building hybrid mobile apps (web technologies wrapped as native applications) and has only just gone from alpha to beta; that said, the repo has been starred nearly 11,000 times and the framework has over 13K followers on Twitter.

Ionic is essentially a wrapper around the already very popular Apache Cordova framework (think PhoneGap), but comes with its own very powerful CLI tools and a wealth of documentation. Particularly impressive for such a new project.

Ionic + AngularJS

According to the Ionic website, the framework is “Performance Obsessed”. Performance issues were the main reason we shied away from PhoneGap and hybrid apps in the past, so this gave us some confidence that it was time to try them again. The framework also comes with a set of very well designed UI components, uses Bower & NPM and is written in AngularJS and SASS (optional), which are some of the most popular tools and frameworks out there and most likely key to Ionic’s popularity.

Getting Started with Ionic

First of all, Ionic is an NPM package, so make sure you have Node and NPM installed and then run:

npm install -g cordova ionic

This will get you set up with the Ionic CLI tools and creating your first boilerplate app can be done with a single command:

ionic start --sass -appname "Airport Parking Shop" --id com.fubra.aps aps_app tabs

Now with the boilerplate app ready, simply ‘cd’ into the newly created app directory and run:

ionic serve

This will start the Ionic server (with live reloading) and launch your newly created app in the default browser!

Ionic Dev Environment

Ionic Project StructureThe boilerplate file structure should be familiar to anyone who has ever used PhoneGap or AngularJS. All the app files, HTML, CSS & JS, reside in the www directory and all the Cordova plugins, SASS etc. in the app’s root directory.

Inside www you’ll see a typical AngularJS app with controllers, templates etc.

Whilst AngularJS knowledge isn’t necessarily essential, it will certainly help a lot and together with the excellent Ionic documentation the learning curve is minimal.

Ionic also provides a very good learning portal at learn.ionicframework.com and sites such as StackOverflow are full of helpful discussions and suggestions.

 

Building the Airport Parking Shop App

Our app uses a simple landing page with a quote form that is made up of a select list and some date/time pickers.

To set up the main view we have a simple route set up in www/js/app.js pointing to our quote.html template and declaring the view’s controller as QuoteCtrl, which we created in the www/js/controllers/ directory:

// Configure routing
.config(function($stateProvider, $urlRouterProvider) {

	// Configure routes
	$stateProvider

		.state('main', {
		url: '/',
		templateUrl: 'templates/quote.html',
		controller: 'QuoteCtrl'
	});

	// Default Route
	$urlRouterProvider.otherwise('/');
})

Next, we wrote the markup for our quote form and started looking at options for the date/time pickers, of which there are lots to choose from. That said, we didn’t really want to introduce another dependency such as jQuery, we wanted something optimised for mobile, and most importantly, we wanted whatever could be implemented the quickest and with the least amount of coding.

The obvious choice then was native HTML5 date and time inputs:

<input type="date"/>
 
<input type="time"/>

They work brilliantly on both iOS and Android (4.4+) and required hardly any work.

The final quote form looked like this:

App View 1

<!-- quote form -->
<div class="row responsive-sm">
    <div class="col col-50 col-offset-25">
        <div class="list box">
            <label class="item item-input item-select item-divider">
                <div class="input-label">
                    <strong>Airport</strong>
                </div>
                <select class="close-left" ng-model="pickers.airport">
                    <option value="ABZ">Aberdeen</option>
                    <option value="BHD">Belfast City (George Best)</option>
                    ... and so on


                </select>
            </label>
        </div>
        <div class="list box">
            <div class="item item-divider">Drop-Off</div>
            <div class="item picker-input">
                <input type="date" ng-model="pickers.startDate" ng-change="updateCleanEnd()" class="date close-right" />
                <input type="time" ng-model="pickers.startTime" class="time" />
            </div>
            <div class="item item-divider">Collect</div>
            <div class="item picker-input">
                <input type="date" ng-model="pickers.endDate" ng-change="setDirty()" class="date close-right" />
                <input type="time" step="60" ng-model="pickers.endTime" ng-change="setDirty()" class="time" />
            </div>
        </div>
    </div>
</div>

With the quote form hooked up to a controller and the picker values working, we were ready to start requesting some data.

We wrote a very basic AngularJS service calling the Airport-Parking-Shop REST API which we already use for the results on our website.

The service uses the AngularJS $http object for the GET request and returns a promise, again using the built in $q object in the AngularJS framework. The core method of the service looked like this:

params.callback = 'JSON_CALLBACK';

// Create promise
var deffered = $q.defer();

// Do request
$http({

	method: 'JSONP',
	url: 'https://www.airport-parking-shop.co.uk/rest-api',
	params: params,
	cache: false

}).success(function(data) {

	// Check results was found
	if (data.status === 200 && data.results.length) {

		// Resolve with success
		deffered.resolve({
			status: 200,
			results: data.results
		});

	} else {

		// Resolve with no content
		deffered.resolve({
			status: 204
		});

	}

	// If error then simply resolve with error
}).error(function() {

	// Resolve with error
	deffered.resolve({
		status: 500
	});

});

An essential feature was to allow the user to go back from this results view and maintain the exact state of the quote form. This could of course be done in many ways using the AngularJS router, cookies etc. but again, instead of setting up more routes and states, we opted for a standard Ionic modal view which again required minimal code to implement and looked like this:

App View 2

<ion-modal-view id="results" ng-controller="ResultsCtrl">
    <!-- Header bar -->
    <div class="bar bar-header bar-positive">
        <!-- Back Button -->
        <button ng-click="modal.hide()" class="button button-positive icon ion-chevron-left"></button>
        <h4 class="title">{{airport}} Parking</h4>
    </div>
    <!-- Main content -->
    <ion-content class="has-header has-subheader" ng-class="{ 'ios' : ios }">
        <!-- Visible when all results is filtered -->
        <div id="bgMsg">No Results</div>
        <!-- Results List -->
        <ion-list>
            <ion-item ng-click="openBrowser('{{item.bookingUrl}}')" target="_blank" ng-repeat="item in results | orderBy:predicate" ng-show="carpark_type[item.parking_type]" class="result item-icon-right">
                <div class="row">
                    <div class="col">
                        <h3>{{item.carpark_name}}</h3>
                        <p>
                            <img src="img/stars/stars_{{item.avg_rating}}.png" class="rating">
                            <i class="{{item.parking_type}} ion-record key"></i>&nbsp;

                            <small>via {{item.partner_name}}</small>
                        </p>
                        <p class="info">
                            <span class="ion-clock">{{item.transfer_time_int}}
                                <span ng-show="item.transfer_time_int != 'N/A'">mins</span>
                            </span>
                            <span class="ion-ios7-loop-strong" ng-show="item.transfer_time_int > 0">{{item.transfer_freq}}</span>
                        </p>
                    </div>
                    <div class="col col-20 price">
                        <div class="loading logo_container" rn-lazy-background="'{{item.logoImage}}'" rn-lazy-loading-class="loading" rn-lazy-loaded-class="loaded"></div>
                        <strong>{{item.amount | currency: "&pound;"}}</strong>
                    </div>
                </div>
            </ion-item>
        </ion-list>
    </ion-content>
</ion-modal-view>

The modal view can then be initialised and controlled with a snippet of JS and allows results to slide over the quote form in a very native looking way, without ever reloading the quote form and thus maintaining the state prior to the user submitting the form. The JS to control the modal view looked something like this:

// Create results modal
$ionicModal.fromTemplateUrl('templates/results.html', {

	scope: $scope,
	animation: 'slide-in-right'

}).then(function(modal) {

	$scope.modal = modal;

});

// Show Results
$scope.modal.show();

Finally, having a working quote form, API service and results view, we needed to find a way to link to car park providers’ websites where the user can either perform the booking or navigate back to the results whilst still maintaining the results and quote form state.

Now, with our JSON results in, we moved on to create a single list view for displaying the results.

Linking to the device’s browser was an option, but this would take the user several steps away from the app and just wasn’t ideal. Luckily, Ionic supports all standard Cordova/PhoneGap plugins, so we opted for the Cordova in-app browser plugin and again, with the help of the Ionic CLI tools, installing this plugin was very straightforward.

ionic plugin add org.apache.cordova.inappbrowser

With the in-app browser installed, displaying the car park provider’s website in a pop-up browser can be done with a snippet of JS which looks something like this:

// Create inappbrowser
 var browser = window.open(url, '_blank', 'enableViewportScale=yes,closebuttoncaption=Back');

Now that we had a fully functioning app running in a desktop browser, it was time to start testing on real devices and finally releasing our app to the masses!

Testing our app

At this point we spent a little over a week writing the code and tweaking the UI to where it felt right and whilst this was all surprisingly easy, the real challenges came once we started testing outside the browser and getting our app ready for distribution.

Ionic’s CLI simplifies testing on devices with 2 commands, namely ionic emulate and ionic run.

To use these commands, you first need to add the platforms you intend to distribute to.
In our case, iOS and Android:

ionic platform add ios
ionic platform add android

This creates the platform specific builds in the platforms/ directory where the app will be compiled into its native form.

To compile and run the app on a device emulator such as Xcode’s iPhone Simulator or the Android SDK Device Emulator, simply run:

ionic emulate ios

Alternatively, to compile and run the app straight onto any connected devices, run:

ionic run ios

Now, whilst the iPhone Simulator that comes bundled with Xcode launches quickly and runs the app as you’d expect, the same cannot be said for Android.

The Android Emulator that comes with the Android SDK is quite simply unusably slow in our experience, so as an alternative we used a nifty app call Genymotion.

The Genymotion app is quick to install and has a completely free option along with some paid options for larger groups of developers. Regardless of the price, this app helped us immensely with testing our app on Android and is simply a must when using Ionic for building Android applications.

One thing to note is that the Genymotion emulator will not launch by using ionic emulate android, but rather ionic run android as if it was a real device.

Once we were all set up and testing on emulators and real devices, it became quite clear that whilst the browser is fantastic for development, it’s quite far off the actual devices and we had quite a few bugs and fixes to iron out.

Another big problem for us was implementing app icons and splash screens. First of all this meant making changes inside the ‘platforms/’ directory, which is something we really would have preferred not to do. Secondly, the way these icons and splash screens were implemented in Ionic simply didn’t match up to either Apple or Android’s specifications.

We ended up using a really helpful site called makeappicon.com, which was able to give us at least a somewhat familiar looking set of icons to those that we found in the Ionic project.

This is something that could do with some serious attention as it took at least 2 days for what should be a very small task. That said, it’s important to remember that Ionic is still in beta and I’m sure that with the current interest and contribution we’ll see this process simplified very soon.

Distributing our app

Two weeks from discovering the Ionic framework, we had an app that was running well on both iOS and Android and we were ready to build and distribute.

Ionic has a very detailed guide to building and publishing for Android here. Luckily building iOS via Xcode is very easy and, seeing as Xcode manages provisioning profiles directly from iTunes Connect, it is most likely the preferred solution regardless of how Ionic would approach this.

Conclusion

So, after waiting for Apple’s ridiculously long review process, we had two apps live and it all took no more than 10 working days to complete.

That is quite impressive and much quicker than any previous app we’ve released, so is Ionic our new default app framework? For the most part yes; however, should a project come along that demands that extra premium feel and isn’t as time restricted, a native app might still win us over. Here’s what we’ve learnt and how we think hybrid apps compare to native apps when using the Ionic framework:

Performance

Whilst our app performs very well, it still uses CSS3 transitions and is more dependent on the user’s device than a native app would be. Something to bear in mind at least.

All in all, hybrid apps are still just slightly behind in terms of performance, but Ionic certainly has done a fantastic job and to most the difference will be negligible.

User Experience (UX)

This is a tricky one, native apps definitely have the advantage when it comes to creating platform specific looking and feeling apps, but customisation can be more complicated. Hybrid apps on the other hand are really easy to customise, but creating a native look and feel can be much more challenging.

Development

Working on our app has been an absolute joy, even compared to the very good Xcode. The time it takes to compile a native app after every code change makes a really big difference and our two weeks would have certainly been a lot longer, not to mention if using Android SDK and Eclipse!

Learning Curve

There’s no question learning AngularJS and the Ionic framework is going to be a much easier task for the average web dev than learning the likes of Objective-C or Java, not to mention that the same web technologies will cover all the platforms you decide to develop for. This is a really big advantage, especially for businesses that need to deal with staff changes, and it is the reason hybrid apps exist in the first place.

Update!

March 24th, 2015: The story continues – click here for how this blog post broke our website and how Nginx and Pagespeed helped fix it!

About Ray Viljoen

Developer, coffee addict and rural seaside-living family man with a passion for anything on 2 wheels. I also write the occasional technical blog post and contribute to the open-source software community.

Related Posts

14 responses to “Discover how we built our app in 2 weeks using Ionic Framework”

  1. Ionic is amazing! I learnt in in just 3 days, and I can create an app with 3 user roles, social sharing, course management, time tracking and location based. To speed things up, I use firebase. Definitely will try to gain a better look at ionic. But so far, wow. Just wow

  2. Did you consider Famo.us in your decision process leading to ionic framework being your solution for this app, and if so, what made you go the ionic road instead of the Famo.us one?
    Thanks

    • Unfortunately we never found famo.us.. not sure how, but having had a few people suggest it, we’ll def be looking into it with our next app.

  3. Did you also investigate Crosswalk? I built an Ionic app last week, and the performance was insane on Crosswalk compared to the standard WebView, even on Kitkat.

    • We had a very brief look at it, but we we’re happy with the Android performance given our limited time. Definitely something we’ll look at with the next release though.

  4. This is more about Cordova/PhoneGap rather than Ionic, but is core to the hybrid apps. Let’s say you wanted to add payment processing so you could pay for parking in your app. Let’s assume there aren’t any existing plugins or they aren’t mature/modern enough. Do you think you would develop the plugins and keep your app hybrid or switch to native?

    • I think it depends entirely on what functionality it was and what the development time would be. Something complicated like payments.., maybe we’d go native. That said, there’s so many phonegap plugins available now that this is probably not a major concern.

  5. The 4.0 release of the Cordova cli tool added some nice support for Icons and Splashcreens. You can just put them in a folder and add their location and size to the config.xml file and the cli will put them in the right place inside the platforms folder at build time.

  6. @brad There’s an interesting thread here about Angular 2.0 and Ionic:
    http://forum.ionicframework.com/t/angular-2-0/1978/11

    Key points are that a) it could be another year away before it’s released, so shouldn’t worry about it too much yet, and b) Ionic are working closely with the Angular team, so any future updates should have good support.

    It may require us to do some refactoring, but given that it only took a couple of weeks to build this particular app, it shouldn’t be a major issue for us. If the app was bigger, it could be more of an issue.

  7. Android Studio is IntelliJ based… Eclipse is a headache, I wouldn’t list it as a con for Android Development scene..

    That said.. I’ve used Ionic, and it’s definitely a far better approach in terms of time-to-market that having to write two separate code-bases… one in Swift/Objective-C and one in Java.

    If you want to achieve more low level stuff, the Mobile OS specific code is going to be unavoidable… but it can be packaged up into a JS API, so UXI’s can get on with the presentation layer and more technical members of the team can get on with the low level integrations.

Leave a Reply

Your email address will not be published. Required fields are marked *

You must be 13 years old or older to comment on this blog.
By submitting your comment, you are agreeing to our privacy policy.