Day 10: PhoneGap--Mobile Development for the Dummies

Today for my 30 day challenge, I decided to learn about mobile development. For a long time, I thought mobile development was fud, and there will be no business model around most of the applications. In fact, writing mobile applications never excited me. However, given the advancements that have happened in the mobile space, and the fact that more people access the internet on mobile devices than desktops, I decided to give mobile development a try. I will be using PhoneGap as my starting point for my mobile development journey.

In this blog post, we will first cover the basics of PhoneGap, and then we will develop a mobile application using the technology.

PhoneGap logo

Mobile Application Usecase

The mobile application that we are going to develop today is a reader application for the 30technologiesin30days challenge. Users can install the application on any of Android, Symbian, webOS, or Windows Phone device. The mobile application is available for download at https://build.phonegap.com/apps/635001/share.

The app can do the following :

  1. Give a listing of all the blogs published in this challenge. When a user clicks any of the item on the list, the link will be open in the browser. 30technologiesin30days mobile app home screen

  2. Readers can share their feedback on the series using the application.

30technologiesin30days mobile app feedback screen

What is PhoneGap?

PhoneGap is a free and open source framework to develop mobile applications using standard web technologies i.e. HTML, CSS, and JavaScript.

It wraps the application web assets inside of native looking app that can be uploaded to the various app stores. Most importantly, we can do cross-platform mobile application development using PhoneGap. This means, ideally we can write a mobile application once, and port the same application to multiple platforms. As an example, I wrote this application for android devices, but using PhoneGap build, the application was packaged for other devices as well. Most of the standard device features like camera, geolocation,storage, etc are available to the developers using a JavaScript API. This JavaScript API provided by PhoneGap is different depending on the targeted mobile platform.

A few facts with noting about PhoneGap :

  1. In 2009, Nitobi developed a Mobile development framework called PhoneGap.
  2. Adobe acquired Nitobi(company behind PhoneGap) in October 2011.
  3. Adobe contributed PhoneGap to the Apache foundation.
  4. The open source project is called Apache Cordova.
  5. PhoneGap is the Adobe implementation of open source Apache Cordova project. The core of PhoneGap uses Apache Cordova.
  6. It has a plugin based architecture. All the device features are available as plugins. We will be using couple of plugins in this blog.

Why should I care?

I considered PhoneGap because:

  1. There is no need to learn native mobile application development for each and every platform. PhoneGap's cross-platform nature saves a lot of time and effort if developers want to target multiple platforms. I know HTML, CSS, and JavaScript so its a smooth entry into the mobile world.

  2. It is a very good for developing CRUD mobile applications running over a REST API.

  3. It does not force a developer to choose one CSS library. The developer is free to choose any mobile library that suits their taste. I am using jQuery mobile for this application.

PhoneGap Prerequisites

PhoneGap requires NodeJS and we will use npm to install PhoneGap. Npm is the package manager for NodeJS. The npm package manager comes by default in newer versions of NodeJS. You can download the latest version of NodeJS from official website.

You have to install the target platform SDK's as well on the machine. For example, if we are building an Android application, then we have to install the Android developer tools on the operating system. PhoneGap uses their SDK to build the package for the target platform.

Getting Started with PhoneGap

To install PhoneGap, just type the following command:

$ sudo npm install -g phonegap

The command shown above will install the phonegap package globally, allowing the phonegap command to be available from any directory.

To install plugins, we need to have Cordova command-line also installed on the machine.

To install Cordova, just type the following command.

$ sudo npm install -g cordova

Github Repository

The code for today's demo application is available on github: 30technologies30days-mobile-app.

Create the PhoneGap application

The phonegap command-line provides a command to create a new template phonegap project. To create a phonegap project, type the following command.

$ phonegap create reader --id io.reader --name Reader30

The above command will create a reader directory on the file system.

The first argument specifies a reader directory to be generated on the file system for the project. The other two arguments are optional: the io.reader argument provides your project with a reverse domain-style identifier, and the Reader30 provides the application's display text.

The reader phonegap application folder structure is shown below:

PhoneGap app folder structure

Let's look at each of the generated folders.

  1. The merges folder offers a place to specify assets to deploy on specific platforms. For example, we might use merges to change the font size for only Android devices.

  2. The platforms directory houses platform build files. Whenever we build a project, the artifacts will be placed under the platforms directory.

  3. The plugins folder stores plugins used by the application. When we install a plugin, the plugin artifacts will be placed in this directory.

  4. The www directory houses the application resourcess like html, css, js, and img files. It is the directory where we will spend most of our time. The config.xml file contains metadata needed to generate and distribute the application. The metadata includes items such as application name, description, author details, app permissions, etc. The full listing is available here.

To run the application on android, run the following command:

$ phonegap run android

It will first build the reader application for the android platform, and then if a device is connected then it will run the template application on the actual device. If the device is not available, the Android emulator will be started and the application will be deployed to the emulator.

PhoneGap android emulator

Note : The performance of the Android emulator is very poor so I recommend you always connect your actual mobile device. For tips on speeding up the Android emulator, take a look at this blog post by Grant Shipley.

Develop the mobile application

Our application has two screens as mentioned above in the Mobile Application Usecase section. We will develop each screen one by one.

Screen 1 : List all blogs

The home screen lists all the blogs published during the challenge. We will start with updating the index.html. Please copy the css and javascript resources from my github repository.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <title>Learn 30 technologies in 30 days</title>
 
  <link rel="stylesheet" href="css/vendor/jquery.mobile-1.3.1.min.css"> 
  <link rel="stylesheet" href="css/vendor/jquery.loadmask.css">
 
</head>
<body>
 
<div data-role="page" id="mainPage">
        <div data-role="header" data-position="fixed">
 
            <h1>30Technologies30Days</h1>
            <a href="#feeback" data-icon="edit" data-theme="b" class="feedback ui-btn-right" data-role="button" data-inline="true" data-ajax="false">Feedback</a>
 
            <div data-role="navbar">
            <ul>
                <li><a href="#home" class="home ui-btn-active" data-icon="home">Home</a></li>
 
            </ul>
        </div>
        </div>
 
 
        <div id="main" data-role="content">
 
        </div>
 
        <div data-theme="a" data-role="footer">
        <h3>
            © Shekhar Gulati 2013
        </h3>
    </div>
</div>
 
<script type="text/x-mustache-template" id="home-template">
  <ul id="blogs" data-role="listview" data-filter="true" data-filter-placeholder="Search blogs..." data-inset="true">
 
  </ul>
</script>
 
<script type="text/x-mustache-template" id="blog-template">
<li>
    <a href="{{url}}" target="_blank">
        <h3>{{title}}</h3>
        <p><strong>{{publishedOn}}</strong></p>
    </li>
</script>
 
 
 
<script src="phonegap.js"></script>
<script src="js/vendor/jquery-1.9.1.min.js"></script>
<script src="js/vendor/jquery.mobile-1.3.1.min.js"></script>
<script src="js/vendor/jquery.ui.map.js"></script>
<script src="js/vendor/jquery.loadmask.min.js"></script>
<script src="js/vendor/jquery.timeago.js"></script>
<script type="text/javascript" src="js/vendor/mustache.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>

The html shown above imports all the required css and javascript files. It uses jQuery mobile to achieve a native look and feel. We also define mustache templates for listing all the blogs.

The application specific javascript exists in the app.js file.

$(document).ready(function(){
    homeView();
    $('.home').on('tap', renderHomeView);   
    $('.feedback').on('tap', renderFeedbackFormView); 
 
});
 
function renderHomeView(event){
    event.preventDefault();
    homeView();
}
 
function homeView(){
    $('#main').empty();
    $('.home').addClass("ui-btn-active");
    $('#main').html(template("home"));
    var url = 'http://30technologiesin30days-t20.rhcloud.com/api/v1/blogs';
    $.mobile.loading( 'show',{});
    $.ajax({
        url : url,
        dataType : 'json',
        success : function(data){
            $.mobile.loading( 'hide',{});
            $.each(data , function(i , obj){
                var template = $("#blog-template").html();
                obj.publishedOn = $.timeago(obj.publishedOn);
                $("#blogs").append(Mustache.to_html(template,obj));
                $('#blogs').listview('refresh');
            });
        },
        error : function(XMLHttpRequest,textStatus, errorThrown) {   
            $.mobile.loading( 'hide',{text:"Fetching blogs.."});  
            alert("Something wrong happended on the server. Try again..");  
 
        }
    })
 
    $('#main').trigger('create');
 
}
 
function template(name) {
        return Mustache.compile($('#'+name+'-template').html());
}
 
function showNotification(message , title){
        if (navigator.notification) {
        navigator.notification.alert(message, null, title, 'OK');
        } else {
            alert(title ? (title + ": " + message) : message);
        }
}

The app.js shown above does the following

  1. It binds to the document ready event. On ready, the home view will be rendered.

  2. The homeview makes a REST call to fetch all the blogs. We use jQuery to make the REST call.

  3. When data is received, we iterate over the data and create a list item for every blog post. Finally, we refresh the listview.

Allow Access to REST service

PhoneGap by default does not allow the application to access remote resources. This means the application can not make REST calls. To allow the application to make REST calls, we have to allow access. We can allow the application to access all the resources using a * wildcard. Refer to the documentation for more information.

Update the access configuration parameter in config.xml

<access origin="*" />

Install plugins

This application uses a couple of plugins to access device specific features.

$ cordova plugin add org.apache.cordova.geolocation
$ cordova plugin add org.apache.cordova.dialogs
  1. The first command installs the geolocation plugin. Geolocation provides information about the device's location, such as latitude and longitude. We will use this later in the post. Refer to documentation for more information.

  2. The second command installs the dialogs plugin. The dialogs plugin provide native visual device notification. Refer to documentation for more information.

Screen 2 : Feedback Submission Form

The second screen allows users to submit feedback on the series.

We add the feedback form to record the feedback.

<script type="text/x-mustache-template" id="feedback-form-template">
 
    <form action="" id="feedbackForm">
            <div data-role="fieldcontain">
                <label for="name">
                    Describe
                </label>
                <input type="text" name="name" id="name" placeholder="Full Name eg. Shekhar Gulati ">
            </div>
            <div data-role="fieldcontain">
                <label for="description">
                    Describe
                </label>
                <textarea name="description" id="description" placeholder="Message for author.."></textarea>
            </div>
            <div id="checkboxes1" data-role="fieldcontain">
 
                <fieldset data-role="controlgroup" data-type="vertical">
                    <legend>
                        Share my location
                    </legend>
                    <input id="sharemylocation" name="sharemylocation" type="checkbox" value="true">
                    <label for="sharemylocation">
                        Share
                    </label>
                </fieldset>
            </div>
            <button id="create-button" data-inline="true">Feedback</button>
        </form>
</script>

The app.js file is updated to listen to tap events on any element within the feedback class. The feedback class is added to the feedback link on the top.

$(document).ready(function(){
    homeView();
    $('.home').on('tap', renderHomeView);   
    $('.feedback').on('tap', renderFeedbackFormView); 
 
});
 
function renderFeedbackFormView(event){
    event.preventDefault();
    $('#main').empty();
    $('#main').html(template("feedback-form"));
    $('#main').trigger('create');
    $('#create-button').bind('tap',shareFeedback);
}
 
function shareFeedback(event){
        event.preventDefault();
        $('#feedbackForm').mask();        
        var name = $('#name').val();
        var description = $('textarea#description').val();
        var sharemylocation = $("#sharemylocation:checked").val() === undefined ? "false" : "true";
        var data = {name:name , description:description , lngLat :[]};
        if(sharemylocation === "true"){
            navigator.geolocation.getCurrentPosition(function(position){
                var lngLat = [position.coords.longitude , position.coords.latitude];
                data.lngLat = lngLat;
                postFeedback(data);
 
            } , function(error){
                    alert('code: '    + error.code    + '\n' +
                      'message: ' + error.message + '\n');
                    $('#feedbackForm').unmask(); 
            });
        }else{
            postFeedback(data);
        }
 
 
 
 
}
 
function postFeedback(data){
    $.ajax({
                type : 'POST',
                url : 'http://30technologiesin30days-t20.rhcloud.com/api/v1/feedback',
                crossDomain : true,
                data : JSON.stringify(data),
                dataType : 'json',
                contentType: "application/json",
                success : function(data){
                    $('#feedbackForm').unmask();
                    $('#feedbackForm')[0].reset();
                    showNotification('Received your feedback', 'Info');
                    homeView();
                },
                error : function(XMLHttpRequest,textStatus, errorThrown) {     
                  $('#feedbackForm').unmask();
                  alert("Error status :"+textStatus);  
                  alert("Error type :"+errorThrown);  
 
                }
        });
}

When the feedback form is submitted we get the data from the form. If the user has checked the sharemylocation checkbox, we the use the geolocation plugin API to fetch the users location. Finally, we submit the POST request to the REST web service. On a successfully feedback submission, we show a notification to the user.

Run the application

Now, we can install and run the application on the device by running the following command.

$ phonegap run android

That's it for today. Keep giving feedback.

What's Next

The info about PhoneGap is very useful, I'm going to try PhoneGap + Jquery mobile too :)

People should consider this before building things with phonegap and jquery-mobile:

http://apachecordova.blogspot.de/2012/11/who-is-murdering-phonegap-its-jquery.html

Hello Shekhar, It's good to see that you have choose the topic related to the latest mobile application development. I think you have applied all the code you have mentioned in the above post. I want to know more on this if you have got some real good updates, so please inform us about that and keep sharing some more exciting news man.