May 2012

Volume 27 Number 05

HTML5 - Develop HTML5 Windows Phone Apps with Apache Cordova

By Colin Eberhardt | May 2012

This article introduces Apache Cordova, a framework for creating cross-platform mobile applications using HTML5 and JavaScript, and shows how it can be used to develop applications for Windows Phone.

Windows Phone and its native development platform allow you to create beautiful Metro-style applications with ease. With the recent Nokia partnership, Windows Phone is starting to find its way into more and more pockets.

Recent data published by research firm Gartner Inc. predicts a promising future for the Microsoft OS (bit.ly/h5Ic32), with significant market share in a fragmented market. If you’re developing a smartphone application, this market fragmentation means you either have to choose which OS to target or write the same application multiple times using the diverse range of languages these phones require (C#, Java and Objective-C).

However, there is another way. All these smartphones have a highly capable browser, in many ways more capable than their desktop counterparts, where some people still use archaic browsers! Modern smartphones allow you to create applications that run within the browser using a combination of HTML5, JavaScript and CSS. With these technologies you can potentially write a single browser-based application that runs across a diverse range of smartphone devices.

Introducing Apache Cordova

You can create an HTML5-based mobile application by creating a public Web page with JavaScript and HTML5 content and directing people to the hosting URL. However, there are a couple of problems with this approach. The first is the distribution model through online marketplaces and stores. You can’t submit the URL that hosts your Web app to a marketplace, so how can you monetize it? The second problem is how to access the phone’s hardware. There are no widely supported browser APIs for accessing phone contacts, notifications, cameras, sensors and so on. Apache Cordova (just Cordova hereafter for brevity) is a free and open source framework that solves both of these problems.

Cordova started life as PhoneGap, which was developed by Nitobi. In October 2011 Nitobi was acquired by Adobe Systems Inc., with the PhoneGap framework being open-sourced under the Apache Software Foundation and rebranded as Cordova. This transition is still underway.

Cordova provides an environment for hosting your HTML5/JavaScript content within a thin native wrapper. For each smartphone OS, it uses a native browser control to render your application content, with the application assets being bundled into the distributable. With Windows Phone, your HTML5 assets are packaged within the XAP file and loaded into isolated storage when your Cordova application starts up. At run time, a WebBrowser control renders your content and executes your JavaScript code.

Cordova also provides a set of standard APIs for accessing the functionality that’s common across different smartphones. Some of these functionalities include:

  • Application lifecycle events
  • Storage (HTML5 local storage and databases)
  • Contacts
  • Camera
  • Geolocation
  • Accelerometer

Each one of the preceding functionalities is exposed as a Java­Script API, which you use from your JavaScript code. Cordova does all the hard work involved in providing the required native implementation, ensuring that you work against the same JavaScript APIs, regardless of the phone OS your code is running on, as illustrated in Figure 1.

Cordova Allows the Same HTML5 Application to Run Across a Range of Mobile OSes
Figure 1 Cordova Allows the Same HTML5 Application to Run Across a Range of Mobile OSes

The bulk of this article discusses Cordova from the perspective of a Windows Phone developer, where development takes place within Visual Studio and you test your application on the emulator or a physical device. While Cordova is a cross-platform technology, you typically develop using your editor or IDE of choice, so an iOS developer would develop a Cordova application in Xcode and an Android developer would most likely use Eclipse.

Cordova also has a cloud-based build service called Build (build.phonegap.com), where you can submit your HTML5/JavaScript content. After a short time it returns distributions for most of the Cordova-supported platforms. This means you don’t need to have copies of the various platform-specific IDEs (or a Mac computer) in order to build your application for a range of platforms. The Build service is the property of Adobe and is currently in beta and free to use. It will remain free for open source projects.

Acquiring the Tools

It’s assumed you already have Visual Studio, the Windows Phone SDK and (optionally) Zune set up for Windows Phone development. If not, you can obtain the tools for free by downloading Visual Studio 2010 Express for Windows Phone (bit.ly/dTsCH2).

You can obtain the latest Cordova developer tools from the PhoneGap Web site (phonegap.com), although future releases will be distributed via Apache (incubator.apache.org/cordova). The download includes the templates, libraries and scripts required to develop Cordova applications across all the supported platforms. You’ll want to use the Windows Phone version, of course.

Once you’ve downloaded the Cordova tools, follow the Windows Phone Get Started Guide (phonegap.com/getstarted/) and install the Visual Studio template. Creating a “Hello World”-style application is as simple as creating a new project based on the supplied template, as shown in Figure 2.

Cordova for Windows Phone Includes a Visual Studio Template
Figure 2 Cordova for Windows Phone Includes a Visual Studio Template

If you build and deploy the project created by the template to your emulator, you should be greeted with the message “Hello Cordova,” as shown in Figure 3.

The Cordova Template Application Running on an Emulator
Figure 3 The Cordova Template Application Running on an Emulator

The Anatomy of a Windows Phone Cordova Application

Although you can develop a Cordova application without much knowledge of how it works under the hood, it’s worthwhile understanding what the various files generated by the template are, as shown in Figure 4.

The Cordova Template Folder Structure
Figure 4 The Cordova Template Folder Structure

Focusing only on the Cordova files in Figure 4 (from top to bottom), note the following:

  • GapLib/WP7CordovaClassLib.dll is the Cordova assembly. This contains the Windows Phone native implementation of the Cordova APIs.
  • www is the folder where you place your application assets, HTML5, JavaScript, CSS and images. The template generates a basic index.html file and the master.css stylesheet.
  • www/cordova-1.5.0.js provides the Windows Phone imple­mentation of the Cordova JavaScript APIs. This interfaces with the native code contained within WP7CordovaClassLib.
  • BuildManifestProcessor.js is a JavaScript file that’s invoked by a post-build step. This file generates the Cordova­SourceDictionary.xml file, ensuring that anything you add to the www folder will be loaded into isolated storage.
  • CordovaSourceDictionary.xml is a generated XML file that lists all of your application assets. When your application first launches, this XML file indicates the files to be loaded into isolated storage.

The MainPage.xaml file contains an instance of the CordovaView control, a user control that contains a WebBrowser control:

<Grid x:Name="LayoutRoot">
    <my:CordovaView Name="PGView" />
  </Grid>

When the app starts, the CordovaView control takes care of loading your application assets into local storage and navigating to the www/index.html file, thus launching your application. You can, of course, place other Silverlight controls in the page by editing this XAML, although I wouldn’t recommend it. If you’re writing an HTML5 application, your intention is probably to make this work cross-platform. Any controls you add to MainPage.xaml will of course be specific to your Windows Phone build.

Developing Cordova Applications

You can add your HTML, JavaScript and CSS files to the www folder and—as long as you mark them with a Build Action of Content—they’ll be included in your project and accessible via the browser control when your application executes. You can use any of the standard JavaScript/HTML5 libraries or frameworks in your Cordova application, as long as they’re compatible with the phone’s browser.

The Cordova APIs are documented on the Cordova Web site; I won’t describe them in detail here. One important thing to note is that you must wait for the deviceready event before making use of any of the other API methods. If you inspect the index.html file generated from the template, you can see that it waits until the device is ready before updating the UI:

<script type="text/javascript">
  document.addEventListener("deviceready",onDeviceReady,false);
  function onDeviceReady()
  {
    document.getElementById("welcomeMsg").innerHTML
      += "Cordova is ready! version=" + window.device.cordova;
    console.log(
      "onDeviceReady. You should see this " +
        "message in Visual Studio's output window.");
  }
</script>

The console object used in the preceding code allows you to add debug output to your application. These messages are sent to the Visual Studio console by Cordova.

Single-Page or Multipage Application Architecture

When building Cordova applications, you can employ two distinct patterns:

  • Multipage applications: In multipage applications, multiple HTML pages are used to represent the various screens of your application. Navigation between pages uses the standard browser mechanics, with links defined by anchor tags. Each HTML page includes script references to the Cordova JavaScript code and your application JavaScript.
  • Single-page applications: In single-page applications, a single HTML file references Cordova and your application JavaScript. Navigation between the various pages of your application is achieved by dynamically updating the rendered HTML. From the perspective of the phone browser, the URL remains the same and there’s no navigation between pages.

The choice you make between these two patterns has a significant impact on the structure of your code.

Generally speaking, the multipage pattern is best suited to applications that mostly comprise static content. With this approach you can take HTML/CSS/JavaScript that’s currently used on your Web site and package it, using Cordova, for delivery to the phone as an application. But the multipage approach has some disadvantages. First, when the browser navigates from one page to the next, it has to reload and parse all the JavaScript associated with the new page. There’s a noticeable pause as the Cordova lifecycle, which creates the link between the JavaScript APIs and C# counterparts, is executed. Second, because your JavaScript code is being reloaded, all application state is lost.

The single-page pattern overcomes the issues associated with the multipage approach. The Cordova and application JavaScript code is loaded just once, resulting in a more responsive UI and removing the need to pass application state from one page to the next. The only disadvantage to this approach is the added complexity, with JavaScript code being required to update the UI when navigation occurs.

The demo application described in this article uses the single-page pattern. For an example of the multipage approach in action, I recommend looking at the DemoGAP CodePlex project (demogap.codeplex.com), which provides a simple demonstration of the Cordova API features within a Windows Phone application.

The Demo Application

The rest of this article describes “Cordova Twitter Search,” a simple Windows Phone application that allows the user to search Twitter based on one or more keywords, as shown in Figure 5.

The Cordova Twitter Search Demo Application
Figure 5 The Cordova Twitter Search Demo Application

As well as Cordova, this application makes use of the following frameworks:

  • jQuery and jQuery Templates: jQuery has become the de facto standard framework for manipulation of the browser Document Object Model (DOM). jQuery templates are plug-ins that Microsoft developed (bit.ly/8ZO2V1), making it easy to create reusable HTML templates that can be rendered to the DOM. Twitter Search uses jQuery templates to define the UI for the various pages within the application.
  • Knockout JS: Knockout is a Model-View-ViewModel (MVVM) framework that makes it easy to construct ViewModels and keep them synchronized with Views in a manner familiar to Silverlight developers. It’s this familiarity that led me to choose Knockout over the numerous other suitable JavaScript UI frameworks.

I won’t be covering Knockout in detail in this article. If you’re interested in learning more about this framework, I recommend reading John Papa’s recent article, “Getting Started with Knockout” (msdn.microsoft.com/magazine/hh781029). And if you aren’t familiar with the MVVM pattern (where have you been hiding?), I recommend this excellent article by Josh Smith: “WPF Apps with the Model-View-ViewModel Design Pattern” (msdn.microsoft.com/magazine/dd419663).

Developing JavaScript Applications with Visual Studio

Before delving into the details of the application, I want to say a few things about JavaScript application development. One of the challenges facing the JavaScript developer is the dynamic nature of the language. With JavaScript you aren’t constrained by a rigid type system; instead, objects can be built dynamically. This poses a challenge to the developers of JavaScript editors and IDEs. With strongly typed languages such as C# and Java, the type information can be used to provide enhanced code navigation, refactoring and IntelliSense. With JavaScript, on the other hand, the lack of type information means that the IDE typically provides far fewer developer aids.

Fortunately, things have improved recently, with Visual Studio 2010 performing pseudo-execution of your JavaScript code in order to determine the “shape” of each object, allowing it to provide JavaScript IntelliSense. In order to take full advantage of the IntelliSense support, we have to provide the IDE with a few “hints” in the form of “references” that tell the IDE which files to include in its pseudo-execution. With the demo project, all files start with a reference comment that tells the IDE to include the intellisense.js file. The content of this file is simply a list of references that ensure the IDE includes all the important application JavaScript files, providing quality IntelliSense support across the application, as shown here:

/// Ensure IntelliSense includes all the files from this project.
///
/// <reference path="app.js" />
/// <reference path="viewModel/ApplicationViewModel.js" />
/// <reference path="viewModel/SearchResultsViewModel.js" />
/// <reference path="viewModel/TweetViewModel.js" />
/// <reference path="viewModel/TwitterSearchViewModel.js" />
/// <reference path="lib/jquery-1.6.4.js" />
/// <reference path="lib/cordova-1.5.0.js" />
/// <reference path="lib/knockout-1.2.1.js" />

JavaScript is a relaxed and forgiving language, with features such as value coercion and semi­colon insertion making it easy to use in a scripting environment. However, these same features often become problematic when managing large quantities of code. For that reason I highly recommend using JSLint, a tool that applies a more rigid set of coding standards to JavaScript. A popular Visual Studio Extension adds JSLint support (jslint4vs2010.codeplex.com), reporting lint errors within the error console. I’ve used JSLint for the Twitter Search application (and virtually every other JavaScript project I’ve worked on).

You might notice a “globals” comment at the start of each JavaScript file within the project. JSLint helps prevent variables “leaking” into global scope by accidental omission of the var keyword. The “globals” comment provides JSLint with a formal definition of which variables are allowed to occupy a global scope.

The MVVM Application Structure

The Twitter Search application is, from the perspective of the phone’s browser control, a single-page application. Conversely, from the user perspective, it has multiple pages, as seen in Figure 5. In order to support this, a Knockout ViewModel is constructed that contains a stack of ViewModel instances, each one representing a page within the application. As the user navigates to a new page, the corresponding ViewModel is added to this stack, and when the user navigates back, the topmost ViewModel is popped off the stack (see Figure 6).

Figure 6 The Knockout ApplicationViewModel

/// <reference path="..//intellisense.js" />
/*globals ko*/
function ApplicationViewModel() {
  /// <summary>
  /// The ViewModel that manages the ViewModel back-stack.
  /// </summary>
  // --- properties
  this.viewModelBackStack = ko.observableArray();
  // --- functions
  this.navigateTo = function (viewModel) {
    this.viewModelBackStack.push(viewModel);
  };
  this.back = function () {
    this.viewModelBackStack.pop();
  };
  this.templateSelector = function (viewModel) {
    return viewModel.template;
  }
}

When the application starts, an instance of the ApplicationViewModel is created and bound to the UI using Knockout:

document.addEventListener("deviceready", initializeViewModel, false);
var application;
function initializeViewModel() {
  application = new ApplicationViewModel();
  ko.applyBindings(application);
}

The UI itself is quite simple, comprising a div element that uses the Knockout template binding to render the ViewModel stack:

<body>
  <h1>Cordova Twitter Search</h1>
  <div class="app"
    data-bind="template: {name: templateSelector,
                          foreach: viewModelBackStack}">
  </div>
</body>

The Knockout template binding works in a similar manner to the Silverlight ItemsControl in that it binds to an array of ViewModel instances and is responsible for generating the View for each via a template. In this case, the templateSelector function is invoked on the ApplicationViewModel in order to determine the named template for each ViewModel.

If you run this application you’ll find that it doesn’t actually do anything—that’s because there aren’t any ViewModels to represent the pages of the application!

The TwitterSearchViewModel

I’ll introduce the first ViewModel, TwitterSearchViewModel, which represents the first page of the application. This ViewModel exposes a few simple observable properties that support the UI, namely the searchTerm, which is bound to the user input field, and isSearching, which is a Boolean observable that disables the search button when the Twitter APIs are being queried via HTTP. It also exposes a search function that’s bound to the search button, in much the same way that you would bind an ICommand to a Button within Silverlight (see Figure 7).

Figure 7 The TwitterSearchViewModel

/// <reference path="..//intellisense.js" />
/*globals $ application ko localStorage SearchResultsViewModel TweetViewModel*/
function TwitterSearchViewModel() {
  /// <summary>
  /// A ViewModel for searching Twitter for a given term.
  /// </summary>
  // --- properties
  this.template = "twitterSearchView";
  this.isSearching = ko.observable(false);
  this.searchTerm = ko.observable("");
  // --- public functions
  this.search = function () {
    /// <summary>
    /// Searches Twitter for the current search term.
    /// </summary>
    // implementation detailed later in this article ...
  };
}

The template property of the ViewModel names the View that’s associated with this ViewModel. This View is described as a jQuery template within the index.html file:

<script type=text/x-jquery-tmpl" charset="utf-8" id="twitterSearchView" 
  <div>
    <form data-bind="submit: search">
      <input type="text"
        data-bind="value: searchTerm, valueUpdate: 'afterkeydown'" />
      <button type="submit"
        data-bind="enable: searchTerm().length > 0 &&
          isSearching() == false">Go</button> 
    </form>     
  </div>
</script>

If you add an instance of the TwitterSearchViewModel to the application ViewModel stack, the application now shows the first page, as shown in Figure 8.

The TwitterSearchViewModel Rendered via the twitterSearchView Template
Figure 8 The TwitterSearchViewModel Rendered via the twitterSearchView Template

Creating a Metro UI with CSS

One of the most striking features of the Windows Phone OS is the Metro design language, which guides all aspects of the phone’s look and feel. This design language, which favors content over chrome, is not only pleasing to the eye, it’s also practical, delivering highly legible interfaces on the small phone form factor.

The current UI, as shown in Figure 8, uses the standard browser styling and as a result isn’t very pleasing to the eye! There are already a few well-established frameworks for creating good-looking mobile UIs using HTML and CSS, such as jQuery Mobile (jquerymobile.com). Currently these frameworks tend to concentrate on emulating the iOS look and feel. A Windows Phone Cordova application could be styled using jQuery Mobile, although it would probably face some user rejection because it simply wouldn’t “fit” with the overall look and feel of the OS.

Fortunately, the chrome-free Metro theme is actually quite easy to replicate using HTML and CSS. In fact, Windows 8 treats HTML as a first-class citizen, allowing you to develop HTML5 Metro applications using the Windows Runtime APIs.

By introducing the correct fonts, font sizes and colors via some simple CSS (shown in Figure 9), you can create a UI that closely follows the Metro theme, as shown in Figure 10.

Figure 9 Code to Follow the Metro Theme

body
{
  background: #000 none repeat scroll 0 0;
  color: #ccc;
  font-family: Segoe WP, sans-serif;
}
h1
{
  font-weight: normal;
  font-size: 42.667px; /* PhoneFontSizeExtraLarge */
}
button
{
  background: black;
  color: white;
  border-color: white;
  border-style: solid;
  padding: 4px 10px;
  border-width: 3px; /* PhoneBorderThickness */
  font-size: 25.333px; /* PhoneFontSizeMediumLarge */
}
input[type="text"]
{
  width: 150px;
  height: 34px;
  padding: 4px;
}

The Twitter Search Application with a Metro CSS Style Applied
Figure 10 The Twitter Search Application with a Metro CSS Style Applied

One final aspect that’s a bit of a giveaway that this is an HTML5 application rather than a native one is that the user can still “pinch” the UI in order to make it zoom. This can be partially solved by adding the following meta property to the index.html page:

<meta name="viewport" content="user-scalable=no" />

This informs the browser that the user isn’t allowed to scale the rendered content. Unfortunately, the way this is implemented by the Windows Phone browser allows the user to scale the content, but snaps back to the original scale when the interaction ends. This doesn’t look terribly good!

I’ve discovered that, by inspecting the visual tree of the WebBrowser control, it’s possible to attach handlers to the manipulation events and prohibit them from bubbling up to the native TileHost that renders the HTML5 content. I’ve published a brief blog post (bit.ly/vU2o1q) that includes a simple utility class that achieves this. But you should use this with caution because it depends on the internal structure of the WebBrowser control, which may well change in future versions of the Windows Phone OS.

Searching Twitter

If you look in more detail at the TwitterSearchViewModel search function, it queries the Twitter APIs via the jQuery “ajax” function, which returns a JSONP response. A TweetViewModel instance is constructed from each of the returned tweets, and these are used to construct a SearchResultsViewModel instance (see Figure 11).

Figure 11 The TwitterSearchViewModel Search Function

this.search = function () {
  /// <summary>
  /// Searches Twitter for the current search term.
  /// </summary>
  this.isSearching(true);
  var url = "https://search.twitter.com/search.json?q=" +
    encodeURIComponent(that.searchTerm());
  var that = this;
  $.ajax({
    dataType: "jsonp",
    url: url,
    success: function (response) {
      // Create an array to hold the results.
      var tweetViewModels = [];
      // Add the new items.
      $.each(response.results, function () {
        var tweet = new TweetViewModel(this);
        tweetViewModels.push(tweet);
      });
      // Navigate to the results ViewModel.
      application.navigateTo(new SearchResultsViewModel(tweetViewModels));
      that.isSearching(false);
    }
  });
};

The SearchResultsViewModel simply contains a list of tweets:

/// <reference path="..//intellisense.js" />
/*globals ko*/
function SearchResultsViewModel(tweetViewModels) {
  /// <summary>
  /// A ViewModel that renders the results of a twitter search.
  /// </summary>
  /// <param name="tweetViewModels">An array of TweetViewModel instances</param>
  // --- properties
  this.template = "searchResultsView";
  this.tweets = ko.observableArray(tweetViewModels);
}

And the TweetViewModel exposes the properties of an individual tweet and a select function that navigates to the individual tweet view, as shown in Figure 12.

Figure 12 The TweetViewModel

/// <reference path="..//intellisense.js" />
/*globals application*/
function TweetViewModel(tweet) {
  /// <summary>
  /// A ViewModel that represents a single tweet
  /// </summary>
  /// <param name="tweet">A tweet as returned by the twitter search API</param>
  // --- properties
  this.template = "tweetDetailView";
  this.author = tweet.from_user;
  this.text = tweet.text;
  this.id = tweet.id;
  this.time = tweet.created_at;
  this.thumbnail = tweet.profile_image_url;
  // --- public functions
  this.select = function () {
    /// <summary>
    /// Selects this tweet, causing the application to navigate to a tweet-view.
    /// </summary>
    application.navigateTo(this);
  };
}

Again, the templates that describe the View for each of these ViewModels are added to the index.html file, as shown in Figure 13.

Figure 13 Adding Templates to the index.html File

<script type=text/x-jquery-tmpl" charset="utf-8" id="searchResultsView">
  <div>
    <ul data-bind="template: {name: 'tweetView',
                              foreach: tweets}"> </ul>
  </div>
</script>
<script type="text/x-jquery-tmpl" charset="utf-8" id="tweetView">
  <li class="tweet"
      data-bind="click: select">
    <div class="thumbnailColumn">
      <img data-bind="attr: {src: thumbnail}"
                             class="thumbnail"/>
    </div>
    <div class="detailsColumn">
      <div class="author"
           data-bind="text: author"/>
      <div class="text"
           data-bind="text: text"/>
      <div class="time"
           data-bind="text: time"/>
    </div>
  </li>
</script>

With this code in place, when the user hits the “go” button to search Twitter, a new SearchResultsViewModel is added to the ViewModel stack. This will automatically result in the searchResultsView template being rendered within the “app” div. However, because the ViewModel stack is rendered via a foreach template binding, this won’t hide the twitterSearchView template instances; instead they’ll be stacked one above the other. This can be solved by the addition of a couple of simple CSS rules:

.app>div
{
  display: none;
}
.app>*:last-child
{
  display: block;
}

The first selector hides all the immediate children of the div marked with the app class, while the second selector, which has a higher precedence, ensures that the last child is shown.

With these CSS rules in place, the Twitter Search application is fully functional and navigable.

Managing the Back Stack

With the current Twitter Search application you can navigate from the search results page to an individual tweet, but if you hit the phone Back button the application immediately exits. This is because the application navigation occurs entirely within a browser control—hence, from the perspective of the Silverlight framework, the application has a single page. This not only results in a poor user experience, it will almost certainly result in the application being rejected if submitted to the Windows Phone Marketplace.

Fortunately, the solution to this problem is straightforward. The ApplicationViewModel contains a stack of ViewModel instances. If there’s more than one ViewModel instance in this stack, you need to handle the hardware Back button press and pop the topmost ViewModel off this stack. Otherwise, you can allow the Silverlight framework to exit the application.

To support this, a backButtonRequired dependent observable is added to the ViewModel:

function ApplicationViewModel() {
  // --- properties
  this.viewModelBackStack = ko.observableArray();
  this.backButtonRequired = ko.dependentObservable(function () {   
    return this.viewModelBackStack().length > 1;
  }, this);
  // --- functions
  // ...
}

When the ViewModel is initialized, you can handle changes to this observable and subscribe to the backbutton events that Cordova supplies. When the event fires, you invoke the back function on the ApplicationViewModel, which pops the topmost ViewModel off the stack. The Knockout template binding takes care of removing the ViewModel’s associated view from the UI and the CSS styling ensures the view that’s now topmost is visible (see Figure 14).

Figure 14 Handling a Back Button Press

function initializeViewModel() {
  application = new ApplicationViewModel();
  ko.applyBindings(application);
  // Handle the back button.
  application.backButtonRequired.subscribe(function (backButtonRequired) {
    if (backButtonRequired) {
      document.addEventListener("backbutton", onBackButton, false);
    } else {
      document.removeEventListener("backbutton", onBackButton, false);
    }
  });
  var viewModel = new TwitterSearchViewModel();
  application.navigateTo(viewModel);
}
function onBackButton() {
  application.back();
}

Because the backbutton event is supplied via Cordova, the code in Figure 14 will work just fine if you execute the app using a different phone OS (as long as the phone itself has a hardware Back button).

State Persistence

We’ll add one final feature to the Twitter Search application: When a search returns successfully, the search term is added to a list of recent searches (see Figure 15).

Figure 15 Adding a Search Term to a List of Recent Searches

function TwitterSearchViewModel() {
  /// <summary>
  /// A ViewModel for searching Twitter for a given term.
  /// </summary>
  // --- properties
  // ... some properties omitted for clarity ...
  this.recentSearches = ko.observableArray();
  // --- functions
  // ... some functions omitted for clarity ...
  this.loadState = function () {
    /// <summary>
    /// Loads the persisted ViewModel state from local storage.
    /// </summary>
    var state = localStorage.getItem("state");
    if (typeof (state) === 'string') {
      $.each(state.split(","), function (index, item) {
        if (item.trim() !== "") {
          that.recentSearches.push(item);
        }
      });
    }
  };
  function saveState() {
    /// <summary>
    /// Saves the ViewModel state to local storage.
    /// </summary>
    localStorage.setItem("state", that.recentSearches().toString());
  }
  function addSearchTermToRecentSearches() {
    /// <summary>
    /// Adds the current search term to the search history.
    /// </summary>
    that.recentSearches.unshift(that.searchTerm());
    saveState();
  }
}

The addSearchTermToRecentSearches function uses the Knockout convenience function, unshift, which adds an item to the start of the array. Whenever a recent search is added, the state is stored using HTML5 local storage. In this case the state of the array is converted to a comma-separated list via the toString function, and converted back via split. A more complex ViewModel would most likely save multiple property values in JSON format.

Interestingly, while the Windows Phone browser does support local storage, this function is turned off when the browser renders pages from isolated storage. In order to make the earlier code work, the Cordova team had to write a “shim” implementation of the local storage APIs that saves the state within the phone’s isolated storage.

With this last change to the Twitter Search application, it’s now fully functional.

Portability Proof: Running on an iPhone

As you can see, the Cordova framework makes it possible to create HTML5-based applications for Windows Phone. It’s also possible to mimic the native Metro look and feel using simple HTML5 and CSS techniques, while frameworks such as Knockout allow you to properly structure your code.

This article has focused on creating applications for Windows Phone, but the Twitter Search application is portable and should run on an iPhone or Android phone without modification. But would a Metro-style application suit these phones?

As a final demonstration of the versatility of this approach, I’ve created an iOS version of the Twitter Search application, using jQuery Mobile to mimic the native look and feel. This makes great use of the MVVM pattern, in that only the View needs to be changed—all the ViewModel logic is exactly the same. Using the cloud-based Build service I was able to create an iOS “ipa” package and install it on an iPhone, all from a Windows machine. You can see the two applications running side by side in Figure 16.

Twitter Search Running on an iPhone and a Windows Phone Device
Figure 16 Twitter Search Running on an iPhone and a Windows Phone Device

The full source code for both the iOS and Windows Phone versions of the application accompanies this article.


Colin Eberhardt is a technical architect at Scott Logic Ltd. and lead architect at Visiblox (visiblox.com), which provides charting controls for a range of Microsoft .NET Framework technologies. You can follow him on Twitter at twitter.com/ColinEberhardt.

Thanks to the following technical experts for reviewing this article:  Olivier BlochGlen Gordon and  Jesse MacFadyen