Most of the companies wanna to create both Android app and iOS app to cover all mobile device visitors. To save effort and time, many companies try to choose hybrid development which can create cross platform apps. The ideal result is coding once and running anywhere. Currently, there are several frameworks to help people create cross platform app, such as Cordova, Adobe Air, IONIC. The best advantage of hybrid development is that we can use HTML5, CSS and Javascript to build the native app for Android device, iOS device, Windows device, etc. Of course, not every framework use HTML and Javascript to implement the cross-platform.

As I already published RSS Reader App Tutorial Series for Android and iOS platform. In this example, I will use Cordova and backbone to build a cross-platform RSS Reader for both Android and iOS platform. The whole project will be implement by HTML5, CSS and Javascript with PhoneGap/Cordova and Backbone (Besides Backbone, Ionic is another good choice which is powered by Angular to write cross-platform apps). If it is the first time for you to use Cordova, you may check this post: Create a Simple IOS App with PhoneGap. I will try my best to create this tutorial as the best Cordova iOS and Android example. Later, you will be able to get the example source code for further learning. I will cover how to create Hybrid iOS and Android app with Cordova in this example.

Now, let’s start to build our RSS Reader project by Cordova and Backbone. First, I will use follow command to create a Cordova/Phonegap project.

cordova create hybridRssReader com.jmsliu.hybridrssreader "Hybrid Rss Reader"

Then we will find a new folder hybridRssReader. This is the project folder. Inside this folder, the structure will look like:
Cordova Project Folder Structure

All hybrid source code is in the www folder. When you build your Cordova project later, you will put all your HTML, Javascript, and CSS files in this folder. The platforms folder will contain all platform specific files. Next step, we will add android and iOS platform into this Cordova project with following command line:

cordova platform add ios
cordova platform add android

After above step, we can find there are two new folders in the platform.

Cordova Project Platforms Folders

If you want to debug your Hybrid app on Android simulator, you can run this command:

cordova emulate android

If you want to debug your Hybrid app on iOS simulator, you can run this command:

cordova emulate iOS

Currently, this project just looks like this:
cordova project on ios simulator

It’s time to build the UI to show a list of posts. The power of hybrid development is that we can use HTML, Javascript, CSS to build the app which can cross android and iOS. It will be a simple task to use HTML and CSS to create a list. The result will look like below:
QQ20151008-1@2x

It will take less than 5 minutes to create above UI if we are using HTML, CSS. This is the advantage of developing Android app and iOS app in hybrid way. Here is the source code:

        <div class="container jms-container">
            <div class="list-group">
                <a href="#" class="list-group-item">
                    <h4 class="list-group-item-heading">Title 1</h4>
                    <p class="list-group-item-text">Content for title 1...</p>
                </a>
                
                <a href="#" class="list-group-item">
                    <h4 class="list-group-item-heading">Title 2</h4>
                    <p class="list-group-item-text">Content for title 2...</p>
                </a>
                
                <a href="#" class="list-group-item">
                    <h4 class="list-group-item-heading">Title 3</h4>
                    <p class="list-group-item-text">Content for title 3...</p>
                </a>
                
                <a href="#" class="list-group-item">
                    <h4 class="list-group-item-heading">Title 4</h4>
                    <p class="list-group-item-text">Content for title 4...</p>
                </a>
            </div>
        </div>

In my project, I will use several open source javascript library.

  • jQuery
  • Underscore
  • Backbone
  • Bootstrap
  • Cordova
  • Require

At the beginning, I will use these library to revamp the normal HTML project into MVC framework, which is the professional way to build web applications or hybrid apps.

Currently, we already know the convenient to build Android app and iOS app with Cordova. Next, we will use backbone to make the app more sophisticated. It will make our app much simple and structured when we implement more features like loading data from server and refreshing the front page.

Why Choose Backbone?

Backbone is a lightweight Javascript MVC framework for web application. But here is one concept which may easily confuse us in Backbone. In the Backbone, it requires us to create Models, Views, and Templates. Actually, The View in Backbone play the Controller’s role, and the Template play the real View role.

Backbone.js and Underscore.js
Before we start writing code, let us make clear about the javascript library dependency. Backbone.js heavily depends on Underscore.js. So we must need to load Underscore.js before we can use Backbone.js library.

What’s Underscore.js
Underscore.js is a utility javascript library, just like jQuery.

Build Web Application With jQuery, Backbone and Underscore
Now, I will change the above html example source code to build the app in MVC structure.

        <div class="container jms-container">
            <div id="title-list-container" class="list-group">
            </div>
        </div>
        
        <script src="js/lib/jquery-1.11.3.js"></script>
        <script src="js/lib/underscore-min.js"></script>
        <script src="js/lib/backbone-min.js"></script>
        
		<script type="text/template" id="item-template">
		<% for(var i=0; i<titleList.length; i++) { %>
			<a href="#" class="list-group-item">
				<h4 class="list-group-item-heading"><%= titleList&#91;i&#93;.title %></h4>
				<p class="list-group-item-text"><%= titleList&#91;i&#93;.desc %></p>
			</a>
        <% } %>
		</script>
		
		<script>
			$(function() {
				var TitleInfoModel = Backbone.Model.extend({
					default: function() {
						return {
							title: "Post Title",
							desc: "Post description"
						};
					}
				});
				
				var TitleCollection = Backbone.Collection.extend({
					model: TitleInfoModel,
					
					renderDummyData: function() {
						for(var i=0; i<10; i++) {
							var title = new TitleInfoModel();
							this.add(&#91;
								{
									title: "Post Title " + i,
									desc: "This the description of title " + i
								}
							&#93;);
						}
					}
				});
				
				var TitleView = Backbone.View.extend({
					titleTemplate: _.template($('#item-template').html()),
					model: new TitleCollection(),
					
					initialize: function() {
			            this.model.renderDummyData();
		            	$("#title-list-container").empty();
		                $("#title-list-container").append(this.titleTemplate({
		                	titleList: this.model.toJSON()
		                }));
					}
				});
				
				var app = new TitleView();
			});
		</script>

As we can see, I move most of the code from HTML into Javascript. In above example source code, I have created three classes:

  • TitleInfoModel: this is the value object which will contain the data for each post.
  • TitleCollection: this is the data model which is a list to contains all post value object (TitleInfoModel)
  • TitleView: this is the view class which will decide how to show the information in html. As I mentioned before, the view class in Backbone actually play the Controller’s role.

So far we have not covered how to get data from server. In above example, I create some dummy data to automatically create 10 post in the collection, and automatically generate the UI basing on the collection.

Why Do We Use RequireJS?

Now, we are facing a big problem. The script tag will load the javascript files in the order encountered in the HTML page. In above example, I load three external javascript files. The inline scripts that come after them are held until all external scripts have loaded and run. The problem here is what if we have 10 or 20 javascript files in the project. If we need to load all js files before we can show the page, it will take a long time before the page is shown, which is the worst user experience.

RequireJS Manages JS Library Dependency

RequireJS library is a way to manage Javascript library dependencies and modular application design. We can use RequireJS to solve the problem. RequireJS will load the javascript libraries dynamically. With RequireJS, we can define the JS library dependency and control which JS libraries will be load at the beginning. Since RequireJS loads scripts asynchronously and out of order for speed, we must define the dependency rules very carefully. Now, I will update the whole project with RequireJS, jQuery, Backbone, and Underscore.

Here is the new folder structure of my Hybrid Rss Reader App project.
Hybrid RequireJS Backbone Project Structure

How to Manage JS Library Dependency in RequireJS

In the new approach, I will only include one javascript “require.js”. Here is the example source code:

        <div class="container jms-container">
            <div id="title-list-container" class="list-group">
            </div>
        </div>
        <script data-main="js/app/config" src="js/lib/require.js"></script>

According to the Require.js official document, the data-main attribute is a special attribute that require.js will check to start loading after the require.js is loaded. In my example, I will load the config.js in js/app folder. Here is the example source code.

require.config({
    baseUrl: 'js',
    paths: {
        app: './app',
        lib: './lib',
        jquery: './lib/jquery-1.11.3',
        bootstrap: './lib/bootstrap.min',
        underscore: './lib/underscore-min',
        backbone: './lib/backbone-min',
        text: './lib/text'
    },

    shim: {
    	underscore: {
			exports: "_"
		},
		
		backbone: {
			deps: ["underscore", "jquery"],
			exports: "Backbone"
		},
		
		bootstrap: {
			deps: ["jquery"]
		}
    }
});

//start the app
require(
	['backbone', 'app/main'],
	function(Backbone, Router) {
	    $(function () {
                window.BackboneRouter = new Router();
                Backbone.history.start({ pushState: false });
            });
	}
);

This javascript file is basically RequireJS syntax. If you don’t know RequireJS, it may be hard to understand. Please check the RequireJS document. In this javascript file, I just do two tasks:

  • 1. Set javascript library dependencies
  • 2. Use Backbone to render the web page after loading the backbone.js and app/main.js

Backbone Single Page Web Application

Backbone is a very good framework. It can help us simply create a well structured single page web application. In my hybrid rss reader app, I am using Backbone as my web application framework. The entry point is the app/main.js. Now, let’s check the example source code:

define(
	[
	    'underscore',
	    'backbone',
	    'jquery'
	],

	function(_, Backbone, $) {
	    var Router = Backbone.Router.extend({
            routes: {
            	'':'titleList',
            },
            
            titleList: function() {
                require(
                	['app/controllers/TitleListView'],
                	function(TitleListView) {
                		new TitleListView();
                	}
                );
            },
	    });
		
	    return Router;
	}
);

In main.js, I define the router, which is Backbone element. You can check Backbone document to understand all Backbone concept. In the routing map, I set titleList function as the entry point. In titleList function definition, I will ask requireJS to load TitleListView.js and initialise a TitleListView object. Actually, TitleListView.js is a controller. It will call TitleCollectionModel.js to get the data, and invoke the TitleItemTemplate.js to present the UI. Here is a abstract of the roles:

  • TitleListView.js (the controller, the Backbone View)
  • TitleCollectionModel.js (the model, the Backbone Model or Collection)
  • TitleItemTemplate.js (the view, the Backbone Template)

Now, let’s check the example source code of TitleListView.js:

define(
	[
	    'underscore',
	    'backbone',
	    'jquery',
	    'text!../views/TitleItemTemplate.html',
	    //'../views/abstract/BaseView',
	    //'../models/abstract/BaseModel',
	    '../models/TitleCollectionModel'
	],

	function(_, Backbone, $, titleItemTemplate, TitleCollection){
		var titleView = Backbone.View.extend({
			id: 'titleList',
			titleTemplate: _.template(titleItemTemplate),
			model: new TitleCollection(),
			events: function (){
	            return _.extend(
            		Backbone.View.prototype.events,
            		{
		            	//'click #filter-btn': 'trigerFilter',
		            	//'submit #searchFormSubmit': 'searchArticle',
		            	//'click #search-btn': 'searchArticle',
		            }
            	);
	        },
			
			initialize: function() {
				this.$el.attr('id', this.id);
                this.model.renderDummyData();
            	$("#title-list-container").empty();
                $("#title-list-container").append(this.titleTemplate({
                	titleList: this.model.toJSON()
                }));
			}
		});
		
		return titleView;
	}
);

This is a pure javascript file. But it looks a little bit strange for people who is not familiar with requireJS and Backbone. requireJS use define() function to make sure all files in the array being loaded and then run the function. In the function, I define a Backbone view. All important jobs are done in the initialise function:

  • Set the view id (for Backbone definition)
  • Generate a set of dummy data in model
  • Bind the data to view template and render the view in container title-list-container div

Now, let me show you the model TitleCollectionModel.js:

define(
	[
	    'underscore',
	    'backbone',
	    'jquery',
	    './vo/TitleVo',
	],
	
	function(_, Backbone, $, TitleVO){
		var titleCollection = Backbone.Collection.extend({
			model: TitleVO,
			
			renderDummyData: function() {
				for(var i=0; i<10; i++) { //ignore this comment >
					this.add([
						{
							title: "Post Title " + i,
							desc: "This the description of title " + i
						}
					]);
				}
			}
		});
		
		return titleCollection;
	}
)

Above is a very simple example to create a list of dummy data. In the controller, I am using following code to bind the data to view template:

this.titleTemplate({
    titleList: this.model.toJSON()
})

The view template looks like this:

<% for(var i=0; i<titleList.length; i++) { %>
	<a href="#" class="list-group-item">
		<h4 class="list-group-item-heading">
		    <%= //ignore this comment >
                        titleList[i].title
                    %>
		</h4>
		<p class="list-group-item-text">
		    <%= //ignore this comment >
                        titleList[i].desc
                    %>
		</p>
	</a>
<% } %>

Right now, we have successfully built hybrid app with Backbond and Cordova. The whole project is well designed in MVC framework. In the future, we will improve this project to be more sophisticated. For example, we will load the data dynamically by AJAX, and render the view dynamically which can give our user a better using experience.

Previous PostNext Post

1 Comment

  1. I didn’t read the entire post but I guess it should work fine. Bookmarked to further reading. Thank you for sharing!

Leave a Reply

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