Building Real-Time, Multi-Platform Mobile Applications: Examples Using Ionic Framework and Firebase

View all articles

One of the major problems companies encounter when making a smartphone application is multiplicative cost of building a native application across different platforms. While savvy front-end developers have tuned into the development of several hybrid platforms that promise to help address this issue, Ionic Framework and Firebase are a dynamic duo that jointly really do give us amazing flexibility in building real-time smartphone applications using JavaScript and HTML5.

This tutorial introduces the capabilities of these multi-plaform mobile development tools and even provides some Ionic and Firebase examples.

Combined, Ionic and Firebase are a great multi-platform development solution.

(Note: This articles assumes some familiarity with the basics of the AngularJS framework. Here’s a great introductory post on AngularJS for those without that background.)

Introducing the Ionic Framework

The Ionic Framework is consists three main components:

  1. A SASS-based UI framework designed and optimized for mobile UIs.
  2. An AngularJS front-end JavaScript framework used to rapidly build scalable and fast applications.
  3. A compiler (Cordova or PhoneGap) for native mobile applications with CSS, HTML, and JavaScript.

The Ionic framework is also packed with lots of useful CSS components out-of-the-box.

Kudos to Ionic for providing extensive documentation, examples, and starter videos to help simplify the learning curve and get developers up and running quickly.

Introducing Firebase

Firebase is a backend-as-a-service schema-less data system that provides real time data syncing without requiring any custom code to be written. Firebase makes much of your back-end development obsolete, thereby significantly reducing multi-platform development time.

Key features and benefits include:

  1. Data changes without code changes. All data changes are published to clients immediately, without any backend code modification needed.
  2. Lots of adapters. There are adapters, with good support and documentation, for all popular JavaScript frameworks, and mobile platform SDKs. (We used AngularFire, which is the AngularJS binding for Firebase, in this article.)
  3. Ease of authentication. Authentication in Firebase is as simple as a single method call, regardless of the authentication method. Supports simple email and password, Google, Facebook, Twitter, or Github based logins.
  4. Offline enabled. All Firebase data is offline-enabled, so an application can be fully (or close to fully) functional in disconnected mode. Applications are automatically synchronized when the connection is restored.
  5. Configuration dashboard. Much of Firebase (security rules, for example) can be easily configured through Firebase’s intuitive dashboard interface.
  6. JSON-centric. In Firebase, all data is stored and retrieved in the form of JSON objects.

Firebase also offers cloud services for hosting the front-end code which can sabe significant time in deployment and maintenance.

It is also worth noting that Firebase was acquired by Google this past October which has given it significantly more attention and visibility.

A Simple Use Case Example: Expense Tracking

Roommates often share expenses and rely on one another in times of need. So, let’s help roommates track their expenses, and help them reconcile at the end of the month.

To make things even more interesting, let’s build a multi-platform mobile application that will provide real-time updates, so they can each monitor expenses as they occur.

This Ionic and Firebase example demonstrates smooth multi-platform app development.

Now that we’ve decided what we want to build and we’ve been introduced to the tools, let’s get started!

Getting Started with Ionic and Firebase

The first thing we need to do is install Ionic. Follow the installation instructions provided on the Ionic Getting Started page. (Note that Ionic has a dependency on NodeJS, so the instructions will require you to install that as well if you don’t already have it on your machine).

The AngularFire 5 minute tutorial is a great place to begin getting familiar with Firebase. And if you’re a “tinkerer” or a tactile learner like me you may want to pull my implementation from GitHub and start playing with the code.

Coding Our Multi-Platform App

For this tutorial, we’re going to use the sample tabs app provided as part of the Ionic installation as the basis for our app. (You can run the sample app with the command ionic start myApp tabs.)

Open the sample tabs app in your favorite IDE (I’m using Webstorm) and let’s start modifying it to build our roommates app.

For our example Ionic and Firebase app, we’ll need the following three screens:

Before creating these screens, let’s remove the “Friends detail screen” provided by default with the sample app as follows:

  1. Delete the www/templates/friend-detail.html file.
  2. In www/js/app.js, remove (or comment out) the state for friend-detail.html.
  3. In www/js/controllers.js, remove the FriendDetailCtrl controller that is referenced in the state we deleted.

Now let’s change the icons and the text of the tab selectors at the bottom of our screen to be the following:

Change the icons and tab text using this example code for Ionic framework.

This is simply done by making the following changes in www/templates/tabs.html:

<ion-tabs class="tabs-icon-top">

  <!-- My Tab -->
  <ion-tab title="My Expense" icon="icon ion-log-in" href="#/tab/dash">

    <ion-nav-view name="tab-dash"></ion-nav-view>

  </ion-tab>

  <!-- Friends Tab -->
  <ion-tab title="Roomie's" icon="icon ion-log-out" href="#/tab/friends">
    <ion-nav-view name="tab-friends"></ion-nav-view>

  </ion-tab>

  <!-- Account -->
  <ion-tab title="Account" icon="icon ion-ios7-gear" href="#/tab/account">

    <ion-nav-view name="tab-account"></ion-nav-view>

  </ion-tab>

</ion-tabs>

Before we hook up our data to the Firebase, let’s create a list and bind it to an array called expenses by adding the following code to www/templates/tab-dash.html:

<ion-view title="My Expenses">  
  <ion-content>
    <ion-list>               
      <ion-item ng-repeat="expense in expenses|filter:user.password.email"
                type="item-text-wrap">
{{expense.label}}
        <span class="badge badge-balanced">{{expense.cost}}</span>
      </ion-item>             
    </ion-list>            
    <div class="card assertive">                   
      <div class="item item-text-wrap">
        Total Spent <span class="badge badge-positive">{{getTotal()}}</span>
      </div>               
    </div>        
  </ion-content>     
  <ion-footer-bar>
    <input ng-model='label' type='text' id='labelInput'
           placeholder='Type a new expense...' />
    <input ng-model='cost' type="number" id="costInput" placeholder='$' />
    <button class="button icon-left ion-plus" ng-click="addExpense($event)">Add</button>
  </ion-footer-bar>   
</ion-view>

We’ll also need to extend the DashCtrl in www/js/controllers.js to include the expenses array, as well as an addExpense method and a getTotal method, as follows:

.controller('DashCtrl', function($scope) {
    $scope.expenses = [{
        by: ‘email’,
        label: ’test’,
        cost: 10
    }];
    $scope.addExpense = function(e) {
        $scope.expenses.push({
            by: < some email > label: $scope.label,
            cost: $scope.cost
        });
        $scope.label = "";
        $scope.cost = 0;
    };
    $scope.getTotal = function() {
        var rtnTotal = 0;
        for (var i = 0; i < $scope.expenses.length; i++) {
            rtnTotal += $scope.expenses[i].cost;
        }
        return rtnTotal;
    };
})

The expenses array is what stores the items in the expense list, the addExpense() method adds a new value to the expenses array, and the getTotal() method gives us the total of all items in the array.

A similar set of changes now needs to be made to tab-friends.html. Try doing this on your own, but if you run into problems, or want to verify that you’ve done this properly, you can refer to my implementation on GitHub.

Hooking in Firebase

You will need a Firebase account. You can signup here for a free Firebase “Hacker Plan”.

One you sign up, you will receive your root url, which will look something like https://<yourfirebase>.firebaseio.com.

Enabling Firebase in our app requires two small mods to our app.

First, we need to include the Firebase scripts in the app’swww/index.html file as follows:

<script src='https://cdn.firebase.com/js/client/1.1.1/firebase.js'></script>
<script src='https://cdn.firebase.com/libs/angularfire/0.8.0/angularfire.min.js'></script>
<script src="js/app.js"></script>

Next, we need to add the Firebase module to our application by adding 'firebase' to the list in our AngularJS 'starter' module:

angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'firebase'])

Firebase is now enabled, just like any other AngularJS module.

The AngularFire 5 minute tutorial will teach you to create data references in controllers. For our demo app, though, I decided to keep these references in a separate service (since this makes it much easier to maintain and update if the root url is changed). To create this service, add the following to www/js/services.js:

.factory('fireBaseData', function($firebase) {
    var ref = new Firebase("https://luminous-fire-3429.firebaseio.com/"),
        refExpenses = new Firebase("https://luminous-fire-3429.firebaseio.com/expenses"),
        refRoomMates = new Firebase("https://luminous-fire-3429.firebaseio.com/room-mates");
    return {
        ref: function() {
            return ref;
        },
        refExpenses: function() {
            return refExpenses;
        },
        refRoomMates: function() {
            return refRoomMates;
        }
    }
});

The above code adds three reference urls. One for the root and two for collections that we have named expenses and room-mates.

Adding a new collection to Firebase is simply done by adding its name to the end of your root url. So to create the expenses collection that we’ll need, all we need is the following:

https://<yourfirebase>.firebaseio.com/expenses

This will create the expenses collection, and we can then start adding objects to it.

OK, now we can hook in the expenses collection from Firebase to replace the “dummy” expenses array we created earlier. This is done by modifying DashCtrl in www/js/controllers.js as follows:

.controller('DashCtrl', function($scope, fireBaseData, $firebase) {
    $scope.expenses = $firebase(fireBaseData.refExpenses()).$asArray();
    $scope.addExpense = function(e) {
        $scope.expenses.$add({
            by: < someemail > ,
            label: $scope.label,
            cost: $scope.cost
        });
        $scope.label = "";
        $scope.cost = 0;
    };

    $scope.getTotal = function() {
        var rtnTotal = 0;
        for (var i = 0; i < $scope.expenses.length; i++) {
            rtnTotal += $scope.expenses[i].cost;
        }
        return rtnTotal;
    };
})

A similar set of changes needs to be made to FriendsCtrl. I again recommend that you try doing this on your own, but if you run into problems, or want to verify that you’ve done this properly, you can refer to my implementation on GitHub.

To verify that it’s working, while running the app on two different clients, add a new expense, and see that it shows up in the list on both clients. If it works… woo-hoo! You’ve now successfully hooked up your Ionic app with Firebase!

You can test your multi-platform app on different devices by connecting a device to your system and running ionic run android or ionic emulate ios. Refer to the Ionic documentation for more information on testing your app.

Account Management and Security with Firebase

Although the basic functionality is now working, one serious issue is that our app is currently completely insecure. The entire world can see your expenses, without any permissions or logins being required. This obviously needs to be addressed.

Firebase provides a powerful yet simple authentication framework using “rules”. There is a lot that can be done using Firebase’s Rules Language. (Refer to the Firebase security documentation for more detail.)

In our case, we will write a very simple rule to block unauthorized users from accessing our data. To do this, open your root url, click on “Security & Rules” in your left action bar, paste the code below in your rules, and click Save.

{
    "rules": {
        ".read": "auth != null",
        ".write": "auth != null"
    }
}

If you run your application now you will notice that there is no data. You can even try to inspect your request by using browser tools and you should see a message in your console stating that you are not authorized to view the data.

Creating User Accounts and Enabling Login

You can authenticate your users by letting them create their own email/password combination, or use any of their existing Google, Facebook, Twitter, or Github login credentials. For email/password authentication, Firebase offers full set of API methods for password change, reset, etc. More information about authentication using Firebase can be found in the Firebase guide.

For our demo app, we will create two user accounts via the Firebase interface. This can be done by going to your Firebase root url and doing the following:

  1. Click the Login & Auth on the left side action bar.
  2. Select the checkbox to Enable Email & Password Authentication.
  3. Scroll down to find the “Add New Accounts Form”
  4. Add your accounts using “Add New User”.

Enabling secure logins is essential when developing multi-platform applications with Ionic and Firebase.

To enable the login interface for your users, first add the following code to www/templates/tab-account.html:

<ion-view title="Account">
  <ion-content>           
    <div class="list" ng-show="showLoginForm">
      <label class="item item-input">
        <span class="input-label">Email</span><input type="text" ng-model="em"/>
      </label>
      <label class="item item-input">
        <span class="input-label">Password</span><input type="password" ng-model="pwd"/>
      </label>
      <button class="button button-block button-positive" ng-click="login(em, pwd)">Login</button>
    </div>            
    <div class="card" ng-hide="showLoginForm">      
      <div class="item item-text-wrap">You are logged in as {{user.password.email}}</div>                
    </div>
    <button class="button button-stable" ng-click="logout()" ng-hide="showLoginForm">Logout</button>
  </ion-content>  
</ion-view>

Then add the following to AccountCtrl in www/controller.js:

.controller('AccountCtrl', function($scope, fireBaseData) {
    $scope.showLoginForm = false; //Checking if user is logged in
    $scope.user = fireBaseData.ref().getAuth();
    if (!$scope.user) {
        $scope.showLoginForm = true;
    }
    //Login method
    $scope.login = function (em, pwd) {
        fireBaseData.ref().authWithPassword({
            email    : em,
            password : pwd
        },function(error, authData) {
            if (error === null) {
                console.log("User ID: " + authData.uid +
                            ", Provider: " + authData.provider);
                $scope.user = fireBaseData.ref().getAuth();
                $scope.showLoginForm = false;
                $scope.$apply();
            } else {
                console.log("Error authenticating user:", error);
            }
        });
    };

    // Logout method
    $scope.logout = function () {
        fireBaseData.ref().unauth();
        $scope.showLoginForm = true;
    };
});

One important thing to be aware of from a security standpoint is that Firebase logins are persistent by default. Therefore, if you want your user to need to login each time the application is started, you will need to modify the Firebase configuration accordingly. To do this, just one time after a successful login, execute the following code:

var r = $firebase(fireBaseData.refRoomMates()).$asArray();
// NOTE: Substitute the email addresses of your two user accounts in the line below
r.$add(["user1@mail.com","user2@mail.com"]);

You can add this in the account controller after successful login, or put a break point after successful login and run it in your console inspector.

Filtering Based on User

The multi-platform mobile app is still missing one important feature though. We want to distinguish your expenses from those of your roommate. Now that we have created two accounts, we just need to filter the data on our views.

We first need to modify the dashCtrl in www/js/controllers.js in order to (a) get the data for the current user into $scope and (b) save any added expenses for the current user:

.controller('DashCtrl', function($scope, fireBaseData, $firebase) {
    $scope.expenses = $firebase(fireBaseData.refExpenses()).$asArray();
    $scope.user = fireBaseData.ref().getAuth();
    // ADD MESSAGE METHOD
    $scope.addExpense = function(e) {
        $scope.expenses.$add({
            by: $scope.user.password.email,
            label: $scope.label,
            cost: $scope.cost
        });
        $scope.label = "";
        $scope.cost = 0;
    };
    $scope.getTotal = function () {
        var rtnTotal = 0;
        for (var i = 0; i < $scope.expenses.length; i++) {
            rtnTotal += $scope.expenses[i].cost;
        }
        return rtnTotal;
    };
})

Next we need to add a filter in www/templates/tab-dash.html to show only the current user’s expenses:

<ion-item ng-repeat="expense in expenses|filter:user.password.email" type="item-text-wrap">

OK, the Home screen is now perfect. A user can only see and add his or her own expenses.

The last and final step is to enable sharing the complete expense list between roommates. To do so, change the www/templates/tab-friends.html to add this filter:

<ion-item ng-repeat="expense in expenses|filter:roomiesEmail" type="item-text-wrap">

Then modify FriendsCtrl in www/controllers.js as follows:

.controller('FriendsCtrl', function($scope, fireBaseData, $firebase) {
    $scope.user = fireBaseData.ref().getAuth();
    $scope.expenses = $firebase(fireBaseData.refExpenses()).$asArray();
    $scope.roomies = $firebase(fireBaseData.refRoomMates()).$asArray();
    $scope.roomies.$loaded().then(function(array) {
        //array = [[set1_rm1_email, set1_rm2_email], [set2_rm1_email, set2_rm2_email] ...]
        for (var i = 0; i < array.length; i++) {
            if (array[i][0] === $scope.user.password.email) {
                $scope.roomiesEmail = array[i][1];
            } else if (array[i][1] === $scope.user.password.email) {
                $scope.roomiesEmail = array[i][0];
            }
        }
        $scope.$apply();
        // NOTE: For simplicity, this demo only supports the 2-roommate use case
    });
    $scope.addExpense = function(e) {
        $scope.expenses.$add({
            by: $scope.roomiesEmail,
            label: $scope.label,
            cost: $scope.cost
        });
        $scope.label = "";
        $scope.cost = 0;
    };
    $scope.getTotal = function () {
        var rtnTotal = 0;
        for (var i = 0; i < $scope.expenses.length; i++) {
            rtnTotal += $scope.expenses[i].cost;
        }
        return rtnTotal;
    };
})

That’s it! Install/update the app on both your device and your roommate’s device and you should be all set!

Wrap Up

Our simple example only begins to scratch the surface of what can be accomplished – and how easily it can be accomplished – using Ionic and Firebase. They truly are a powerful duo for building real-time, multi-platform smartphone applications using JavaScript and HTML5.

About the author

Avinash Kaza, United States
member since October 17, 2013
Avinash is a senior developer with experience designing & developing data visualizations that answer difficult questions by using the latest tools like HTML5 Canvas. A seasoned product development expert who coaches teams on collaboration while figuring out the best solutions to difficult problems. [click to continue...]
Hiring? Meet the Top 10 Freelance Front-End Developers for Hire in September 2016

Comments

blrbr
This looks great. I will do this tutorial for sure.
Francisco Claria
Nice article :) and awesome combination of technologies!! Is there a way to add business logic at Firebase (serverside) level to avoid unwanted data or operations to be performed by a malicious user?
Avinash
@Francisco check out the rule based security on Firebase : https://www.firebase.com/docs/security/guide/
Serge Zinin
The first picture is awesome, play the game: "Find 10 Differences"
Kaue Machado
Not really Francisco. Unlike Parse, Firebase doesn't support "serverside code", which I don't think is bad at all. As Avinash said, there there is the Security Rules on firebase that makes sure that no unwanted transactions are made. Furthermore, you can setup a back-end app that executes firebase queries.
Francisco Claria
Thanks for clarifying that Kaue! Best :)
Krishnayan Swami
I am using cordova with ionic and this is working like a charm. on the other side, Phonegap can be considered for developing apps if you are short of time to deploy your apps across multiple platform. But when it comes to performance its not the one that can be recommended. Application that are not graphically heavy is a good fit. I did develop couple of <a href="http://www.mobilepundits.com/PhoneGap_Development.html">apps in phonegap</a> but found it be too slow.
Cyrus
Havent actually tried the code myself, but after reading through this, it seems like your getTotal function returns the total of all expenses and not that of the filtered list. Other than that, very good writeup. I've recently started using Ionic and found it fairly easy as Angular is pretty much what I've been doing the past few years, but I never heard of firebase. When I read it here, I was amazed. The reactivity is similar to MeteorJS but they handle hosting for you and I am assuming because they got the hosting setup, their authorization setup already has email servers configured for the forgot password and email verification. That's pretty neat! And its not that expensive if you compare it to hosting services. Pretty awesome! Thanks for this writeup, pretty keen to get going into hybrid development.
Avinash
Thank you Cyrus, I have used MeteorJS and their deployment environment as well, am very impressed with what they are doing too
Avinash
Hi Swami, how recently did you compare the speeds? They have come a long way in this regard, try it one more time if you have not done so recently Just to avoid confusion for other readers, PhoneGap is renamed as Apache Cordova and ionic uses Cordova under the hood to compile angular based web app code into mobile apps
Andrew Alex
Do you have any tool tip or an example set of how to make Expense Tracking offline in the local network without the need for internet.
Andrew Alex
@franciscoclaria:disqus
bill steiner
I loaded your code and can't figure out how to login to demo the app. also there is no sql create statements for the demo tables if i wanted to use my own firebase account. thanks.
Sampath Lokuge
Only the colour.No other differences. Lol :D
John Negoita
This is a great tutorial. I did not know about Firebase, but I will dig into it as it sounds very interesting I've only recently started with hybrid mobile apps I just love Ionic and AngularJS, they do a perfect job. I would like to share my own Crystal Ball app using Ionic and AngularJS - here's a step by step guide on how I did it together with the source code http://www.coding-dude.com/wp/mobile-apps/building-a-crystal-ball-mobile-app-with-angularjs-and-ionic/
bbsmk
blue is 42598b red is b02f41 difference is 7f2a4a
yustein
what happens if you are offline???
Tamil Selvi
Currently getTotal() is adding all the expenses. How to add expenses for a particular user. While listing the expenses, filter:user.password.email is filtering only the particular users expenses. But total is adding all the expenses in the table. Can u help me to fix it?
Surya prakash chaturvedi
why you ask to delete www/templates/friend-detail.html file and commented our some of lines. very ambiguous tut Cant understand.!!!
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Avinash Kaza
JavaScript Developer
Avinash is a senior developer with experience designing & developing data visualizations that answer difficult questions by using the latest tools like HTML5 Canvas. A seasoned product development expert who coaches teams on collaboration while figuring out the best solutions to difficult problems.