A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

HTML/JavaScript Universal Apps: A First Look

For me, one of the most exciting and long-anticipated announcements from last week’s //BUILD conference is the upcoming ability to write Windows Phone 8.1 apps using HTML and JavaScript.

As a web developer, I spend a tremendous amount of time every day writing client-side code that runs in a web browser. I have made a huge investment in mastering these skills and keeping up with emerging trends and “best practices”. The declarative layout and rendering languages of the web, HTML and CSS, are widely known standards that for the most part work identically between platforms (albeit, with a few platform-specific idiosyncrasies). So, it makes perfect sense to me that HTML5 is the best solution for writing cross-platform apps.

Windows Phone 8.1, due for release later this month with widespread over-the-air updates happening this summer, will finally have parity with its tablet/desktop siblings in the ability to run WinRT apps.  This app model allows developers to use the language of their choice to develop apps, from C++ to .NET to HTML/JavaScript.

Since Windows 8.1 and Windows Phone 8.1 will share the same app model (as will the Xbox One, it was announced), the natural question is: Can I write my apps once and have them just work on each platform?  The answer, for the most part, is ‘Yes’, using a new solution type called Universal Apps.

Starting with Visual Studio 2013.2, you will find new project types for creating Universal Apps:

image

Creating a new Universal App project will make a solution with three projects inside: a Windows app project, a Windows Phone app project, and a Shared Code project:

image

Most of your application’s code will go into the Shared project. But, here’s where reality sets in: because a phone is different than a tablet/desktop, both in screen size, memory, and general platform capabilities, it is necessary to maintain some platform-specific pieces within their own project types.  So, any artifact that exists in a platform-specific project will override the same file from the shared project at build time.

For HTML/JavaScript apps, this primarily means maintaining different stylesheets between projects. But, in my tests, there are a few other things that didn’t “just work” while converting an existing Windows 8.1 app into a Universal App. These differences may require some code refactoring in order to separate the features that are only available on a particular platform from the rest of your shared code.

Incompatibilities that I’ve found:

  • No SettingsFlyout: In Windows 8.1 Apps, settings are maintained within flyouts that are accessed from the Settings Charm. This does not seem to be implemented on the phone, so you will need to find an alternative way for the user to specify settings, and refactor your codebase accordingly.

  • Web Fonts: It is very easy to bring a new font into a HTML/JavaScript Windows 8.1 app using Web Fonts (fonts that are temporarily used, but not installed to the system).  For my Windows 8 tablet/desktop apps, I’ve been using Embedded OpenType fonts (.eot).  This format does not appear to be supported on mobile Internet Explorer 11 (which is what the phone’s HTML/JS app container is based upon).  However, the Web Open Font Format (.woff) does work. [UPDATED]

  • Advertisements: In my Windows 8.1 games that are in the Windows Store, I use Microsoft’s advertising platform to earn a little bit of revenue from an otherwise free-to-play game. The Ad SDK is available for use within the Windows project, but not the phone project. Note: This incompatibility is for HTML/JavaScript project types only. The C# project type, for example, does provide an Ad SDK for phone apps.

  • Audio: My games make use of audio, as you would expect, for things like click feedback, explosions, etc. This is relatively straight forward using the HTML5 Audio element/object. Since I don’t have 8.1 installed on actual hardware, I’ve only been able to test using the Windows Phone emulator in Visual Studio. In those tests, there are severe synchronization issues with HTML5 audio. Sometimes sound never plays, and sometimes there is a lag of a few seconds before a sound finally plays. It seems to be a memory management/caching thing, because once a sound has played for the first time, there’s usually little lag if that same file needs to play again within several seconds. [Confirmed on Device – Nokia Lumia 928, delays exist]

    [Update]
    The issue with audio lag may be how I was initializing the code. For example, to play a sound effect from JavaScript, I’ve been using code in my Windows apps like:
    var sfx_click = new Audio("/audio/menuclick.mp3");
    sfx_click.msAudioCategory = "GameEffects";
    sfx_click.volume = 0.8;
    sfx_click.play();
    

    I found a remark on MSDN that states:
    You must set the msAudioCatogery before setting the src property in code.

    So, I have rewritten the above to now look like:

    var sfx_click = new Audio();
    sfx_click.msAudioCategory = "GameEffects";
    sfx_click.src = "/audio/menuclick.mp3";
    sfx_click.volume = 0.8;
    sfx_click.play();
    


    Though I am still experimenting, this seems to have greatly improved the lag situation (so explosions happen at the appropriate time, etc).
  • NuGet: Integration with NuGet seems a bit weird, if not incomplete. You can add a package to the platform-specific projects individually, but not to the shared project. And, NuGet itself seems to get confused, because even though the package is added to the packages folder, none of the artifacts (scripts, css, etc) get created within the project itself. So, if there’s a library that I need to use in both places, what feels natural is to use NuGet to install the packages, and then use “Add Existing” to include files from the platform project’s packages folder into the shared project… but, this means that those artifacts are not truly maintained by NuGet.  If there’s then an update to the package, then I’ll need to manually repeat the process.

  • Windows.ApplicationModel.Store.CurrentApp.getAppReceiptAsync(): It seems, at least at the moment, that the XML returned from the Windows store differs from the XML returned from the Phone store. Specifically, the Phone document includes a default xmlns on the document element, while the Windows document does not (so, code that uses XPath queries will need to be handled conditionally depending on the platform).
  • Speech API: While converting Knave Craps to the phone, I came across an “Access Denied” error while initializing the Speech Synthesizer. I’m trying to come up with a workaround or find out the root cause.  The line of code that resulted in the exception:
    var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();