Platinum Partner
mobile,android,ios,cordova,html

How to Build an iOS and Android App in 24 hours with HTML5 and Cordova


What can one create during the New Year and Christmas holidays? As it turned down – quite enough. Even if you have two kids and a bunch of family members whom you want to visit. The only thing you cannot accomplish in time is to finish an article for Dzone. It takes a lot of time, nearly the entire January.

By the 5th of January I had a laptop and a couple of days to spend on some development. Having estimated what I can do here, I decided to create a mobile app that would work faster than the original. For this, I needed to find communicative creators of a popular app.

Hence, I found a “Spender ” app in the App Store. It is a simple app for tracking your budget. With it, you can estimate how effectively you spend your money in the end of each month. By the 5th of January, this app was in Top-10 in the Russian App Store. I also found their dev-story on iphones.ru. 

In their dev-story, the developers wrote that after completing their previous project, they had three-four free days. So, they decided to create a new app during this free time. Their Product Manager and programmers helped them with positioning the app and its key features.

This encouraged me and I began to think how to create nearly the same app in 2 days.

Note: the original app was updated in the middle of January, and now it looks a little different from my app. Anyway, you can find its screenshots in the dev-story.

I already had the experience of mobile app development using C# and Cocoa. Since this was my personal free time, I wanted to use it with maximum effectiveness. Even If I didn’t succeed, I was eager to learn a new framework or programming language.

I was working for DevExpress from 2006 till2011 and have been reading their announces since I left the company. So, I knew that they created a mobile js-framework based on Cordova/PhoneGap. They made it after I left the company, so I was curious to try it.

The Gartner research company reports that by August, 2013 most of the enterprise mobile software was created using PhoneGap or PhoneGap-based products (like Kony). From my consumer experience, it's far from true. Maybe I was wrong?

I'm not so good at HTML and JavaScript. I can create mark-up with stackoverflow.com and I can write simple selectors with jQuery. I can also find the required information in their documentation. In other words, HTML+JS was a gap in my knowledge and I was ready to fill it or gain some experience.

Thus, I planned to create a cross-platform application that could become an advantage over the original iOS-only Spender app. Moreover, I wanted to spend my time in the most effective way. On the one hand, I had a potentially effective JS framework, on the other – a lack of JS experience. I hoped that the JS framework advantages could balance my poor experience.

Since I like to use a VCS during development, I'll try to recover my progress.

You can download complete apps here:

iOS , Android 

I'm not sure I can provide public access to my repo, because it contains images I bought from Fotolia and third-party libraries, each with a difference license. I'm not a lawyer, so I’d prefer not to take the risk. The most curious of you can take a look into the app bundle itself. JS wasn't minified.

Place: Tula, Russia, Date: January, 5, 2014

+20 minutes Spent on installing Node.JS and Cordova CLI
+10 minutes Downloaded a template app from Cordova. Added a template from PhoneJS. Created a Git-repo, registered it in WebStorm. Added a new record to the httpd.conf in order to have an ability to debug my future app in the browser.
+38 minutes Changed the app namespace to "io.nikitin.ThriftBox". Added navigation. PhoneJS is an MVC-framework. Each app screen is represented as a collection of HTML markup (Views) and fabric function (ViewModel). Here is how it looks at its simplest

<div data-options="dxView : { name: 'home', title: 'Home' } ">
    <div data-options="dxContent : { targetPlaceholder: 'content' } ">
    // View Content
    </div>
</div>

and

ThriftBox.home = function (params) { // Request parameters taken from uri
  return {}; // ViewModel instance
};

Then View and View Model are bound via knockout-bindings. To be in time, I create only two screens: expense input and monthly expense report.

+4 hours 20 minutes Here I got stuck for the first time. I couldn't create a markup of digit buttons.
The original app had a huge keyboard that looked like a calculator or dialer.



I found out that it was not that easy to create such a keyboard, even using a table tag. In the iPhone Retina screen, 1px borders between buttons changed their colors after clicking on the buttons. On my iPhone, the difference in colors was very noticeable. I had to invent how to tackle this.


I tried to implement buttons using divs. But I couldn't achieve a border width of 1 px and make all buttons look equal in different screens. Three hours later I gave up the idea of using divs and moved forward.

+28 minutes Removing a clicked button indicator on iOS. iOS displays a gray indicator around tapped links and objects with the onclick event handler. Since I had my own indicator of a tapped object (the tapped button became darker), I didn't need the default indicator. I solved this problem using the dxAction event:

was:

<td data-bind="click: function() { buttonPress('1') }">1</td>

became:

<td data-bind="dxAction: function() { buttonPress('1') }">1</td>

This event is an extended variation of a "click" event: its handler supports URI navigation between Views and correctly works in the scrollable area.

+14 minutes The buttonPress event handler shown in the previous example now validates numbers from user input.

    var number = ko.observable(null);
    var isValidNumber = ko.computed(function() {
        return  number() && parseFloat(number()) > 0;
    });

    ......

    function buttonPress(button) {
        if (button) {
            if (number())
                number(number() + button);
            else
                number(button);
        } else if (number())
            number(number().substr(0, number().length - 1));
    }

    var viewModel = {
        number: number,
        isValidNumber: isValidNumber,

        viewShowing: viewShowing,
        buttonPress: buttonPress
    };

    .....  

+8 minutes Added a FastClick.js, which removes a delay between tapping the screen and raising the 'click' event on phones. The mobile browser delays the raising of the click event by default to be sure the end-user will not perform a double tap. For the end-user, this looks as if the app is sluggish. You click buttons much faster than an app responds. FastClick.js handles the touchstart event and then creates all the click event process logic.

BTW, adding this library was a mistake; later I'll tell why.

+4 minutes Added a limitation to the length of user input numbers. Corrected the font size for a better look-and-feel.

+58 minutes Added a choice of an expense category. Added a scrollable pane with available categories below the input field. Video.

It took less time than it could be. In the PhoneJS component collection, I found dxTileView. It provides a kinetic scrolling with the required appearance out-of-the-box. It's not easy to implement kinetic scrolling by yourself and thus it’s great that this scrolling is enabled for iOS only - Android doesn't have it.

<div class="category" data-bind="dxTileView: {
                                      dataSource: categories,
                                      itemMargin: 0,
                                      baseItemHeight: 72,
                                      baseItemWidth: 72,
                                      listHeight: 72
                                    }">
    <div class="tile"
         data-options="dxTemplate: { name:'item' }"
         data-bind="css: { selected: $parent.category() == $data },
                    click: function() { $parent.category($data) }">
        <div><img data-bind="attr: { src: image }"/></div>
        <div data-bind="text: name"></div>
    </div>
</div>

It was 7:40 pm, so, I decided to continue the next day.

Place: Tula, Russia, Date: January, 5, 2014

+3 hours 9 minutes Storing data on a local storage. PhoneJS contains classes for working with data: selection, filtering, sorting, and grouping. There are several approaches to store data: Odata and LocalStorage. I didn't want to implement a server side for a free app, and decided to use LocalStorage. Later I found out that this was not an ideal decision. For example, when updating to iOS 5.1 user data is erased, other people complained that LocalStorage is cleared regularly or even when shutting the device down. I didn't want to risk, so I used File API of PhoneGap. 

Documentation says that this API is based on W3C File API. In fact, this means that this API differs in Safari for Mac OS, Chrome for Mac OS, Cordova for iOS and Cordova for Android. File API implementation is different for iOS and Android. E.g. Android implementation doesn't contain the 'Blob' class and 'window.PERMANENT' constant. iI however implements the 'LocalFileSystem' and 'LocalFileSystem.PERSISTENT' classes. The laptop browser provides additional API for requesting an additional storage space, which mobile browsers don't provide.

The available documentation for this API adds more problems. I found several articles searching by "html5 file api". And, I couldn't find an article that would cover all my questions. Finally I created a new class for working with FileAPI. This class supports Cordova 3.3 on iOS, Android, and Chrome 32 for Mac OS and Windows 8. You can find it here: https://github.com/chebum/fileStorage-for-Phone.JS/blob/master/fileStorage.js

You can use it as follows:

//  In this example I create data/records file in the Documents folder of the app
FS.initFileAPI(1000000, true)
    .then(function () {
        var records = new FS.FileArrayStore({ key: "id", fileName: "records" });
        return records.insert({ customer: "Peter" })
     })
     .then(function () {
        alert("Record saved!");
     });

// Or use low-level API:
FS.initFileAPI(100000, true)
    .then(function() {
        return FS.writeFile("file1", "file content")
    })
    .then(function() {
        alert("File Saved!");
    });


+33 minutes Saving the added records to the storage. Category list is stored in ArrayStore, to simplify the selection operations.
+26 minutes Creating layout for the app's Views. PhoneJS provides several Layouts that are the placeholders for the views. My app's start page didn't fit into any of the available layout, so I have chosen the EmptyLayout. But, it doesn't provide animation effects when navigating through views. I copied the EmptyLayout code and added an attribute that had animation effects.
+1 h. 51 min. Template's About screen was redesigned to a report screen, empty by that moment. Created a viewModel that selects data for a current month. Added localization date formatting for the screen caption.
+59 minutes Added the display of expenses grouped by categories for a current month.
+28 minutes Added the selection of months for which the report should be generated. End-users can tap the screen header to select the required month.
+1 h. 20 min. Added Cordova-plugin Statusbar that didn't work outof-the-box. I found that the reference to cordova.js was commented in the PhoneJS app template:

<!--<script type="text/javascript" src="cordova.js"></script>-->

As a result, the native part of my app didn't work.

+39 minutes In the report screen, the upper part was changed to dxToolbar.
+22 minutes I discoveredwhy the dxButton click event handler didn't work. Removing the FastClick.js solved my problem, but caused a delay between tapping and event raising. I've changed the dxAction event subscription to 'touchstart'.
+25 minutes Formatting output strings when generating a report.

At night I dreamed of crappy buttons in the application’s main screen. 

Places: Tula, Vnukovo Airport, Date: January, 7-8, 2014

I had an early flight to Budapest from Vnukovo, and because I had no time in the afternoon, I gradually completed at the airport at night. As you know, it’s not very comfortable to sleep or sit in a café chair for a long time, but it turned out that programming was OK.
+2 h. 5 min. In the morning, I decided to split the buttons in order to remove borders between them. I took the iOS dialer keyboard as a sample.


I created three keyboards. The button size changes depending on screen resolution: for 3.5'', 4'' and 5'' phones. Each table cell contained a div with configured alignment.

Because of the lack of an incomplete vertical text alignment in HTML, the final CSS style for buttons ended to be quite complex:

.home-view .buttons td div {
    color: #4a5360;
    border: 1px solid #4a5360;
    text-align: center;

    position: absolute;
    left: 50%;

    /* Small buttons - default */
    font-size: 26px;
    padding: 13px 0 13px 0;
    width: 52px;
    line-height: 26px;
    border-radius: 26px;

    margin-left: -27px;
    margin-top: -27px;
}


+1 h. 50 minutes I bought several vector icon sets on Fotolia. I cut the required icons and converted them to PNG. It took me quite a long time, maybe, because it was 1.30 am :)

+1 hour 10 minutes Added a splash-screen for the app.

+36 minutes Created three sizes for the app icon. Localized the app name for iOS.

+20 minutes Hiding the splash screen after the app is completely loaded.

+2 hours Fixing multiple bugs.

+2 hours Creating screenshots for Play Store

+30 minutes Creating screenshots for App Store

+30 minutes Writing an App description for two app stores.

+1 h. 30 minutes Submitting my app to the App Store. Here I faced with an issue with the app certification.

My accountancy

Let's summarize the time I spent and divide it into categories.

Development: 21 hours 37 minutes

Graphics and texts: 8 hours 26 minutes

Totally: 30 hours 3 minutes

As a result, I got a minimum-feature working app, though it is not as cool as the latest version of "Spender". I couldn't create splitting expenses by days and income input. My app's UI could be more elegant as well.

After analyzing the original 'Spender' developer work, I got the following. They say that they involved four developers for three-four days. It is about 96-128 man-hours. I spent only 30 man-hours and got an app for three mobile platforms. iOS and Android versions are already in stores. The version for Windows Phone 8 requires a UI redesign.

I can be proud of myself :).
You can download complete apps here:iOS , Android 

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}