Porting a Windows Store App using HTML to Cordova
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:
- Create your project using a Multi-Device Hybrid App sample app that uses WinJS.
- Open it in VS, manually copy over your code, and get rid of any sample code that you don't need.
- Update the app lifecycle code to use Cordova events.
- Rewrite code that requires the use of a plugin.
- Test the CSS in the various emulators. Use the merges folder for platform-specific CSS, if necessary.
- 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).
Comments
Anonymous
August 29, 2014
Howdy Mike - You wrote a awesome thing .It really helped me a lot .I just need a bit more help from u .In my project i 'm using <x-ms-webview> but this does not work fine with android .So where to write the Android specific code for webview . Before giving answer consider me as novice .Anonymous
August 30, 2014
Hi Amit, The way to write platform-specific code in Cordova is to use the merges folder. In VS, merges is a top-level folder. See the subheading "Using merges to customize each platform" in this topic: cordova.apache.org/.../guide_cli_index.md.html Cordova generates a WebView native project when you build, so if hosting the x-ms-webview within the native WebView doesn't work for some reason, you might try it on Android using the same code as on other platforms, and see if the app works without the x-ms-webview.Anonymous
September 07, 2014
Howdy Mike, Thanks for your response , But actually i didn't got u .Can u please elucidate it a bit more , what i had understood is that i can't use <x-ms-webview> for android purpose . Please response asap i have to submit a project .Anonymous
September 08, 2014
It appears from this page (msdn.microsoft.com/.../br211377.aspx) that the x-ms-webview element is part of the Windows Runtime, not Windows Library for JavaScript, so it wouldn't be supported in a Cordova app. If you need to embed a WebView within a Cordova app (which is already implemented as a native WebView on Android), it looks like you would be going down a more platform-specific development path: see the "Development Paths" section in this topic: cordova.apache.org/.../guide_overview_index.md.htmlAnonymous
September 08, 2014
There are a few stackoverflow threads about using WebViews in a Cordova app. You might want to take a look: stackoverflow.com/.../embedding-webview-to-a-cordova-projectAnonymous
October 23, 2014
Hi there, the sample is nice but it DOES NOT use the 'backbutton' anywhere in the code... am I wrong? I had actually tried something similar with newest cordova 4.0 and WinJS 3.0.1 releases and it seem there's no way to detect 'backbutton' nor native 'backclick' events! Can you provide a working example/update this template? That's the only thing separating me from having a working universal app! Hope you can help soon Thank youAnonymous
October 24, 2014
The comment has been removedAnonymous
February 08, 2015
Hi, I'm just porting a cordova application to windows (windows phone and windows) using the Universal plateform configuration. And I'm encountering an issue using the backbutton fonctionnality. While running cordova automatically add the WinJS link to DOM just after the cordova.js. Should I have to mannually add th WinJS before cordova ? is there a mistake here. Note that the back button is not working by default. I also tried to bind myself to the backclick event of WinJS.Application and this doesn't work anyway. RegardsAnonymous
February 10, 2015
@kbeaugrand, as of CTP3 for VS Tools for Apache Cordova, output from a Cordova app for Win/WinPhone 8.1 is a Universal App. And you should be able to open this in Visual Studio as a Universal App project (which is useful if you are porting; otherwise, you don't want to edit the output). Is that how you ported it to a Universal App? If not, you might try it. If the BackButton was working prior to porting and doesn't work after porting (which seems a little unlikely), I would suggest using BackButton code from the Universal App Navigation Template. If you can't identify the problem, the harder fix is to use the Universal App Navigation Template as a starting point for your app instead of the generated Cordova project. The downside is you'd need to do a manual migration, basically the reverse of what is described in this blog post. (The generated Universal App project is in bldDebugplatformswindows, once you are able to build it against Windows). If you are having issues building the Cordova app for Windows, please see my latest post on running Cordova apps on Windows and WinPhone 8.1; unless you are adding a lot of platform code, it is possible you don't need to port the app at all to make it work.