Visual Studio recently released a preview for Multi-Device Hybrid Apps, that allows you to create Cordova apps in Visual Studio. Cordova is a cross-platform API and build toolset that provides access to native device APIs using HTML, CSS, and JavaScript. If you've already created a Windows Store app using HTML and JavaScript, you can port your app to Android and iOS by using Cordova. The easiest way to move the project to Cordova is to create a Multi-Device Hybrid App in Visual Studio using the open source version of WinJS (Windows Library for JavaScript).

Out of the box, the Multi-Device Hybrid Apps extension for Visual Studio includes only the Blank template. I took one of the more popular Windows Store templates, the Navigation App template, and ported it to Cordova. This template is available here. In this post, I thought I'd share what I learned in that process.

Before going through the porting process, you can evaluate your app for the likely ease, or difficulty, of making it work in Cordova. Here are some of the main considerations:

  • Are there a lot of calls to Windows Runtime APIs? Cordova in VS supports the WinJS APIs, but native Windows Runtime APIs (Windows.* namespace) won't work in a Cordova app. For app lifecycle code and a few other common events, Cordova has APIs that you can use instead. For other native code, you may need to use a Cordova plugin to replace the native APIs, and code your app using the plugin's interface (JavaScript APIs).
  • If you need to use a Cordova plugin for access to native APIs (for example, Geolocation or Camera APIs), check whether the feature is supported in a core plugin or a third-party plugin. Core plugins typically support all the most common target platforms; in third-party plugins, platform support varies. If plugin support is not already available for the native feature, work will be required to create a custom plugin (or to extend an existing plugin) before your app will work in Cordova. Creating a custom plugin will involve writing native code for the platform(s) that you are going to support.
  • Are you using any third-party frameworks besides WinJS? Some frameworks may have incompatibilities with specific platforms or with Cordova.

The main steps involved in porting your app to Cordova:

  1. Create your project using a Multi-Device Hybrid App sample app that uses WinJS.
  2. Open it in VS, manually copy over your code, and get rid of any sample code that you don't need.
  3. Update the app lifecycle code to use Cordova events.
  4. Rewrite code that requires the use of a plugin.
  5. Test the CSS in the various emulators. Use the merges folder for platform-specific CSS, if necessary.
  6. Update images in platform resource files.


1. Create your project using a Multi-Device Hybrid App sample

Instead of using the Blank template included with Cordova, start with one of these sample apps; the apps listed here simplify the setup of the open source WinJS. A custom PowerShell script in the project file will automatically download and include WinJS when you build the project.

  • Cordova Navigation Template (WinJS). This is a port of the Windows Store Navigation App template, and provides a simple multi-page app with page animations and Back button support. It includes the Windows Store navigator.js file.
  • ToDoList sample using WinJS. This sample provides local storage using HTML5 Web Storage, cloud-storage using Azure Mobile Services, and geolocation using Bing Maps. Note that this sample uses TypeScript out of the box.

2. Manually copy your HTML, JavaScript, and CSS code, and get rid of sample code you don't need

No shortcuts here, but it's not hard for smaller apps. Cordova uses an index.html file instead of default.html. If you use the out-of-the-box Cordova project structure, you will naturally need to update script and internal URI references;  for example, in calls to WinJS.Navigation.navigate.


3. Update the app lifecycle code

The app lifecycle code in a Windows Store app likely includes one or more calls to Windows Runtime APIs. You need to replace these with Cordova APIs, such as the deviceready event handler. Here is an example of app lifecycle code from the Cordova Navigation Template. This code eliminates the need to call the Windows.ApplicationModel.Activation API.


(function () {
    "use strict";

    var app = WinJS.Application;
    var nav = WinJS.Navigation;
    var sched = WinJS.Utilities.Scheduler;
    var ui = WinJS.UI;

    document.addEventListener("deviceready", onReady, false);
    document.addEventListener("resume", onResume, false);

    function onReady() {
        // Handle the deviceready event.
        initialize();
    }
    function onResume() {
        // Handle the resume event
    }

    function initialize() {

        nav.history = app.sessionState.history || {};
        nav.history.current.initialPlaceholder = true;

        // Optimize the load of the application and
        // while the splash screen is shown,
       
// execute high priority scheduled work.
        ui.disableAnimations();
        var p = ui.processAll().then(function () {
            return nav.navigate(nav.location || Application.navigator.home, nav.state);
        }).then(function () {
            return sched.requestDrain(sched.Priority.aboveNormal + 1);
        }).then(function () {
            ui.enableAnimations();
        });

    }

})();


4. Rewrite code that requires use of a plugin

If your app requires extensive use of one or more plugins, this step will likely involve the most work. If it requires only plugins that already work on all target platforms, especially the core plugins, comparatively less work will be required.

To support certain types of changes you made to the package.manifest file in the new app (before you ported it), you may have to use a plugin.
Cordova provides some handy APIs for a few events such as backbutton. If you can use these events instead of native APIs, you don't need to use a plugin. For more info, see Events.


5. Test and update the CSS

You're in the web developer world now! You will need to test your app on the different platforms and deal with browser differences in CSS implementations. Fortunately, WinJS should handle most of this, but there are exceptions. For example, Webkit-based browsers (Android, iOS) don't currently support the CSS3 grid layout, so you may need to use a flexbox in your app instead.

The Ripple Emulator will provide quick and easy testing of layout and CSS on Android and iOS. But, of course, to really verify your app you will need to do testing on platform emulators and devices.

The best practice for handling differences in display size (and orientation changes) is to use @media rules. For example, the following CSS applies to display sizes <500 px in width. Here, you override margin values for the .fragment header CSS selector.


@media (max-width:499px) {
    .fragment header[role=banner] {
        margin-left: 15px;
        margin-right: 30px;
    }
}

If necessary, use the merges folder to provide platform-specific CSS values. Cordova recommends using an overrides.css file for this purpose. When you use overrides, you should include an empty overrides.css in the project's css folder.

WinJS provides ui-dark.css and ui-light.css as style templates. You will need to decide which one provides the look you want in your app and whether you want the app to look the same on all platforms. If not, you will need to decide how much extra effort you want to invest to make the app look like a native app on all target platforms.


6. Update images in platform resource files

Android and iOS include device-specific files for the splashscreen and icons. The sample apps include these files, but the art will need to be updated for your app.


Finally -- Test, package, and publish


Packaging and publishing is platform-specific. For more info, see the documentation.

VS for Multi-Device Hybrid Apps doesn't support debugging Windows Phone targets in the current release (but that is coming, I'm told). So, if you're porting from a Windows Store app, you may choose to test, package, and publish for Windows Phone using your native Windows Store project (requires Windows 8.1 for phone support).