Porting Counting Beads Web App to Android* using PhoneGap* compatible API and Windows 8* Store App

Tweet Like

Table of Content

  1. Introduction and Source Code
  2. Porting to Microsoft* Internet Explorer* 9
  3. Handling Browser Window Resizing and Different Device Size
  4. Initialization for a PhoneGap App
  5. Porting to Android Devices
  6. Porting to Windows 8 Store App

Introduction and Source Code

Counting Beads app is originally a web HTML5 app and downloadable from Tizen* developers site. The final version can be downloaded from github sample-counting-beads, or register the Intel(R) XDK to check out all the HTML5 samples.

The Counting Beads app is created using HTML5, JavaScript, CSS3, and jQuery*. It has the the following characteristics:

  • Works on in Google* Chrome* browser only - Does not work on Android* devices as a PhoneGap* compatible app
  • Uses CSS media query for different layout of different devices
  • Absolute positions are used for all element layouts

The app is a simple educational game for children to learn how to count. "Touch" on the beads will make the beads move to the other side. When the number of beads in that color reach the number displayed on the left side, it will display a kudo message in the number box or a "*" on a smaller screen device.

This article is explaining the process and issues encountered when porting the original web app to a mobile device app.

The goals for this porting task are:

  • Runs on a Google Android device: tested on Sumsung* Galaxy* S2 phone & Google* Nexus*
  • Runs on a Windows 8* tablet: tested on Microsoft* BUILD tablet

The following images are the introduction screen before and after porting to Microsoft* Internet Explorer* 9 (IE9).

in IE9 before in IE9 after
Before porting After porting

The following is game screen in IE9 after porting (before porting you can not get to this game screen because the [start] button is not shown):
Counting Beads Ported to IE 9

Porting to Microsoft* Internet Explorer* 9

In order to port the Counting Beads app as a Windows 8 store app, the first thing is to port it to work with Internet Explorer 9.

Besides changing all the absolute positions to relative positions which is a lot of tedious work and testing, the major incompatible issues encountered are below:

  1. -webkit-mask-image
    On the start screen, there is a logo displayed using "-webkit-mask-image" originally. It has to be replaced with "background-image" instead. The end result is not as great comparing to the version in Chrome but it does show the logo instead of blank.
    You can see the differences below:
    original logo img modified logo img
    In Chrome In IE9
  2. "z" index
    "z" is not recognized by IE9, replacing it with "z-index" works.
  3. HTML5 dataset support
    HTML5 dataset is not supported by IE9 but it was not caught by any validation tool. So it was difficult to isolate. We used IE9 developer tools to identify the issue. The fix is fairly simple, see below:
    One place is in function "populateBars(fromPage)" inside file countingBeads.js:
    Original code:
    function handleBeadClick(event)
    {
    	var target = event.target;
    	var row = target.dataset.x;
    	var col = target.dataset.y;
        ......
    }

    See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

    Modified code:
    function handleBeadClick(event)
    {
        var target = event.target;
        var row;
        var col;
        if(target.dataset) {
    	    row = target.dataset.x;
    	    col = target.dataset.y;
        } else {
    	    row = target.getAttribute('data-x');
    	    col = target.getAttribute('data-y');
        }
        ......
    }

    See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

During the porting, the following tools are very helpful:

  • IE9 developer tools

Handling Browser Window Resizing and Different Device Size

The CSS media query is wonderful for adjusting the layout according to different browser window sizes and device screen sizes. But the beads are drawn dynamically in JavaScript. So we need to catch the window resize event and draw the beads. But we only want to handle the last resize event when the browser window gets resized. Thankfully we found this nice little plugin jQuery throttle & debounce plugin created by Ben Alman. With the plugin, all we have to do is to handle the last resize event. It is very simple. The same code works when the device orientation changes.

First include the plugin library in the "index.html" after jquery:

<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="js/jquery.ba-throttle-debounce.js"></script>

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Then in the initialization function "init()" set the resize event handler using debounce like below:

function init() 
{
    if (init_done)
        return; 
    init_done = true; 

    $(window).resize($.debounce(250, handleResizeWin));
    ......
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Initialization for a PhoneGap compatible App

The original sample is a web app so the data initialization is done when document ready event is fired. e.g.:

$(document).ready(function()
{
	init();
});

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

But for a PhoneGap compatible app, the data initialization should be done through PhoneGap's "deviceready" event.

document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log("onDeviceReady: Phonegap version " + window.device.cordova);
	init();
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

This is causing a problem. Because you can never know which event fires first, the PhoneGap "deviceready" event or the document ready event.

What we did here is not perfect, once we discovered a better mechanism, we will update this article. Right now we use a setTimeout in the document ready event like below:

$(document).ready(function()
{
    console.log("*****document.ready and init.");

    // call init() to initialize data
    // it should be called only once. 
    // But when using PhoneGap, "DeviceReady" event is usually fired after this call. So use setTimeout().
    setTimeout("init()", 1000);
});

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Porting to Android Devices

During the porting, we have encountered many issues and all except one issue has been worked out:

  1. html5 audio tag is not supported on the Android devices tested.
    Maybe this will change in the future, but currently we used PhoneGap media object to play the music.
    if (window.device) // if phonegap is used: 
    {
        if (phoneCheck.android) // android
            this.mediaobj = new Media("/android_asset/www/audiomp3/" + id + ".mp3", this.mediaCallSuccess, this.mediaCallError);
    } else
        this.mediaobj = document.getElementById(id);

    See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

  2. html5 audio tag supports looping but PhoneGap media object does not.
    In the index.html, the music for the introduction screen plays in loop. But there is no equivalent functionality with PhoneGap 2.0 that will work the same. So when the app runs on a Android device, the music for the introduction screen will play only once. Hopefully the future version of PhoneGap will support the loopy feature, or even better if the webkit inside Android device would support audio tag.
    <audio id="introMusicLoop" loop="true" preload="auto"><source src="audiomp3/introMusicLoop.mp3" type="audio/mp3" /></audio>

    See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

  3. iframe tag is causing problem on the newer Android devices.
    This app has a license page that is displayed using the "iframe" tag. It works nicely inside a browser, but it is not functioning on the Android devices as a PhoneGap app.
    On Google Nexus the app will stop at the introduction screen; and on Sumsung* Galaxy* S2, the app works but if you click the license button, the button disappears.
    So "iframe" is removed from the "index.html" and is added dynamically in the JavaScript when the app runs in a browser. When the app runs as a PhoneGap app, it uses jQuery .get function:
    function loadLicenseTxt() {
        if (typeof window.device !== "undefined") { // running in PhoneGap
    
            $.get('README.txt', function (data) {
                var divLicense = document.getElementById("licensetext");
                divLicense.innerText = data;
            });
        }  else {
            // running as web app from Browser, so use iframe to display the README.txt
            console.log("***Test: read README.txt iframe");
    
            var licPage = document.getElementById("licensepage");
            var licEle = document.getElementById("licensetext");
    
            var frmEle = document.createElement("iframe");
    
            // Web page 
            frmEle.setAttribute("src", "README.txt");
    
            frmEle.style.height = window.innerHeight * 0.88 + "px";
            frmEle.style.width = window.innerWidth * 0.995 + "px";
    
            licPage.replaceChild(frmEle, licEle);
    
            frmEle.setAttribute('id', "licensetext");
        }
    }

    See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

    Although the code can be simplified to use "$.get()", in order to keep it like the original app in the Chrome browser, "iframe" is used still but dynamically.

Porting to Windows 8 Store App

Please see article Porting the HTML5 Samples to Windows 8* Store for detail information.

Возможность комментирования русскоязычного контента была отключена. Подробнее. Закон о блогерах