Switching platform targets in Visual Studio

One of the most important things to know when working in Cordova is how to switch between target platforms. There aren't obvious controls in Visual Studio for this, but it's there. Either use the Build > Configuration Manager menu item, click the Debug/Release drop-down in the toolbar and select Configuration Manager:

cordova1-1

Once you're there, the Active Solution Platforms drop-down is where you set your target.

cordova1-2

Doing this will change the main VS toolbar to reflect options available for that target. This is how you switch between targets and run the app on devices and emulators.

Tip: to shortcut this you can add the platform drop-down directly to the toolbar. Right click the toolbar and select Customize at the bottom of the long list. In the dialog that appears, click the Commands tab, then select Toolbar and Standard:

cordova1-6

Now click Add Command, then pick Build > Solution Platforms:

cordova1-7

This adds the platform drop down to the toolbar. You might need to use the Move Down button in the Customize dialog to place it where you want. I also used the Modify Selection button to narrow the size to 130, and placing it where I wanted I see this on my toolbar:

cordova1-8

Running the app, and first issues encountered: varying CSS support

With everything migrated now, I was able to run the app on the Local Machine (Windows) as expected. The one caveat I found is that Cordova at present targets Windows 8.0 and not 8.1 (I think Cordova version 3.6 is supposed to do 8.1), which means that it doesn't understand variable-sized views, and only snapped/filled states. This means that in a narrower view that's later than 320px you get the 320px snapped view inside the wider view like you do with any Windows 8.0 app on 8.1.

On Windows Phone the app ran great in portrait mode, but the layout wasn't working in landscape. Hard to tell why, because the present Cordova targets Windows Phone 8.0 which means the app is running inside a webview inside a Silverlight app. This means there's no debugger support whatsoever, so I can't poke into the DOM to see what's going on.

On Android the layout is all wrong…because an Android webview in which a Cordova app runs doesn't support the CSS3 grid specification as we enjoy on Windows. Urk. I've relied heavily on grid layout but clearly I'll have to convert to flexbox, which is why I said CSS comes up early.

On iOS (in the Ripple emulator), looks like we have the same issue.

The upshot here is that when working in Cordova, your HTML/CSS work is going to be very much like writing responsive web pages for different browsers, because that's really what's happening with Cordova: your code is running inside a webview which has varying capabilities depending on the target platform. 

 

Finding your DOM in the Ripple Emulator

When running on my Android device, Visual Studio's DOM Explorer works just like it does for a Windows app–you can do in and tweak styles and so forth.

cordova1-3

When running in the Ripple emulator, you still get the DOM Explorer except that you see everything that's showing in the emulator, including all the surrounding controls:

cordova1-4

Egads! Where is my app? Well, the easy way to find it is through that click-to-select button in the upper left above: click that, then click in the emulator, and you'll see the DOM tree expand to where your app is. You'll see that it's located under the sections ui > middle > device-container > viewport container > and then the iframe "document":

cordova1-5

 

What's very cool in the DOM Explorer is that the CSS editor does inherently known what styles are and aren't supported for that target device. I can see right away, for instance, that display: -ms-grid; isn't among those supported for Android and iOS webviews, which isn't at all surprising. So the next job is to convert my grid-based CSS to cross-platform flexbox, which will be the next post.


I said that CSS would come in early, but the first thing to discuss in migrating the Here My Am! files from my existing Windows Store app project to a Cordova project. For this I'm just starting with the HereMyAm2a code from Chapter 2 of my free ebook. And in fact I'll keep it simple for starters and just migrate the HTML and CSS, leaving off the JS code for now.

Preliminary notes/build environment

Although I'd started working on a universal Windows app migration for this project, it's not a necessary step for working with Cordova, because it also produces cross-platform apps that will work on Windows and Windows Phone alike, as well as iOS and Android. With Cordova, you let plugins worry about platform-specific things–you don't want that kind of code in your project. 

In addition, it's helpful to know that you don't need a Mac as a build server to work with Cordova until you really want to produce an app for the store. With the Visual Studio extension installed, you can run a Cordova app directly in the Ripple emulator , which is very cool in that you can switch between devices, resolutions, and orientations (including between target platforms) much like Blend for Visual Studio does for Windows, so you can see just how (badly) your CSS is performing.

For myself, I'm working on a Surface Pro 3 as my main machine, have a Windows Phone hanging off it, have an Asus MemoPad7 as an Android dev device, which I wrote about recently. My team has a Mac laptop set up in one of my co-worker's offices as a build server (also for Xamarin) which I can get to over VPN to the Microsoft corpnet from my home office…pretty cool!

Project structure

I started with a new Cordova project (File > New > Project > JavaScript > Multi-Device Hybrid App > Blank App (Apache Cordova)); this is what you want to do rather than trying to convert an existing Windows project. I then migrated the appropriate files over:

Windows Project File Cordova Project File
default.html index.html (This is the default; you can use default.html if you change the start page in config.xml)
js/default.js scripts/index.js (didn't migrate the code yet; the project template uses scripts instead of js as a folder…I might change this later)
package.appxmanifest config.xml (the Cordova generic manifest)
css/default.css css/index.css
html/map.html html/map.html (there is no default html folder, so I created one just to hold this file for the time being)
images/taphere.scale-100.png images/taphere.png; I'll be switching to draw this with a canvas later on, so it's just a placeholder.
images/<logos> Not migrated yet as these need to be specific for each platform, whcih I haven't done yet.
WinJS references WinJS is not a cross-platform, open-source library, an instead of having it in the project references I downloaded WinJS 3.0 and brought it directly into the project:

  • /css/frameworks/ui-dark.css (you'll get a whole ton of warnings on styles in here because of the differences in CSS support between platforms)
  • /css/fonts/Symbols.ttf (ui-dark.css and ui-light.css assume this file is in ../fonts, so it needs to be in a sibling folder unless you modify the reference)
  • /scripts/frameworks/base.js
  • /scripts/frameworks/ui.js
  • /scripts/frameworks/WinJS.js

I don't know how much of WinJS I'll be using, but given that I have lots of experience in this area, it seemed like a good opportunity to keep up! Plus the ui-dark.css has styling that I'm used to with this app. We'll see how it goes.

  The project template also includes a merges folder for platform-specific code, and a res folder for resources that I'll get to later on.

 

Updating index.html

With this migrated project, I fixed up the references in index.html to bring in the appropriate files:

    <link href="css/frameworks/ui-dark.css" rel="stylesheet" />    
    <link href="css/index.css" rel="stylesheet" />    

    <!-- Cordova standard -->
    <script src="cordova.js"></script>

    <!-- WinJS -->
    <script src="scripts/frameworks/base.js"></script>
    <script src="scripts/frameworks/ui.js"></script>
    <script src="scripts/frameworks/winjs.js"></script>

    <!-- Project references -->
    <script src="scripts/platformOverrides.js"></script>
    <script src="scripts/index.js"></script>

Note: in a Windows project, especially with WinJS page controls, it's usually helpful to prefix all references with a leading /. You do not want to do this with Cordova because it doesn't work. I'll have to see what happens later on when I try using page controls.

Note also that you need the reference to cordova.js even though it doesn't exist in your project.

With my script/css references fixed up, I just use the same markup as before in index.html:

<body>
    <div id="mainContent">
        <header id="header" aria-label="Header content" role="banner">
            <h1 class="titlearea "> 
                <span class="pagetitle">Here My Am!</span>
            </h1>
        </header>
        <section id="section" aria-label="Main content" role="main">
            <div id="photoSection" class="subsection" aria-label="Photo section">
                <h2 class="group-title" role="heading">Photo</h2>
                <img id="photo" class="graphic" src="images/taphere.png" alt="Tap to capture image from camera" role="img" />
            </div>
            <div id="locationSection" class="subsection" aria-label="Location section">
                <h2 class="group-title" role="heading">Location</h2>
                <div id="map" class="graphic" aria-label="Map"></div>
            </div>
        </section>
    </div>
</body>

 

Up next, running the app.


With my new role as a Content Developer in Microsoft's Developer Division, I'm working now with cross-platform tools like Apache Cordova and Xamarin, and dabbling a little in Unity, and also looking at the Visual Studio ALM tools and how they apply to these project types.

To help myself ramp up on Cordova, I'm in the process of migrating Here My Am!, the app that I build throughout the pages of Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, to Cordova. I can already see there will be numerous challenges to overcome, which I'll try to write about as I work through them (preview: the first post or two will be about CSS). 

For all this I'm using the Multi-Device Hybrid Apps Extension (Preview) for Visual Studio 2013 Update 3 (how's that for a name!). One thing that's immediately clear about the extension is that it saves a whole lot of trouble in getting a Cordova environment set up. Normally you have to go get a bunch of downloads from nine different places, some of which have installers and some of which are just ZIP files, and then you have to install them in the right order figure out how to configure each one with the right environment variables. The extension does that for you.

The documentation for the extension is found on http://msdn.microsoft.com/en-us/library/dn771545.aspx; the installer page specifically describes what pieces it downloads and how to do the configuration, manually. My team is, in fact, the one that produces this documentation–more to come!


With the introduction of universal Windows apps at //build 2014, and the announcement of Windows Phone 8.1 that includes support for writing apps in HTML, CSS, and JavaScript, we do have some resources that are starting to emerge.

First, my newly-released second edition, http://aka.ms/BrockschmidtBook2, is very applicable to Phone apps. I didn't have time to spell out all the differences, but there is a summary of what to watch out for in Chapter 1, namely a few differences in controls and some parts of WinRT that aren't on the Phone.

Second, watch the Building Apps for Windows Blog for material in this area. For example, an upcoming post will spell out the controls story between Windows (WinJS 2.0) and Windows Phone (WinJS 2.1).

Third, Josh Williams and Ryan Salva did a demo session on building a universal app with HTML, CSS, and JavaScript at //build, which you can find on http://channel9.msdn.com/Events/Build/2014/2-540. What you'll see is that they do nearly all of the work in the Shared folder of the VS project, making only one small change at the end of the session to switch the Hub control in the Windows Store app to Pivot in the Phone app…the two controls, in fact, are identical in their API except for the top-level object names, so you just change the names and voila! You're in business.

Finally, there is a post on the Visual Studio blog on universal apps: http://blogs.msdn.com/b/visualstudio/archive/2014/04/08/building-windows-phone-8-1-apps-in-html.aspx.

More is certainly to come.


Another migration issue that I ran into with Windows 8.1 came out when changing the Windows 8 snapped view for the Here My Am! app in my book to variable view sizing. In particular, when I sized the view down to a width below 500px, I noticed that the fonts for h1, h2, and h3 elements no longer adjusted automatically with Windows 8.1/WinJS 2.0.

The reason for this is that the following block of CSS that is present in the WinJS 1.0 ui-dark.css/ui-light.css stylesheets was removed for WinJS 2.0:

@media screen and (-ms-view-state: snapped) { 
    h1, .win-type-xx-large {
        font-size:2 0pt;
        font-weight: 200;
        line-height: 1.2;
    }

    h2, .win-type-x-large {
        font-size: 11pt;
        font-weight: 600;
        line-height: 1.3636;
    }

    h3, .win-type-x-large {
        font-size: 11pt;
        font-weight: 400;
        line-height: 1.3636;
    }

    h1.win-type-ellipsis, .win-type-xx-large.win-type-ellipsis {
        line-height: 1.5;
    }

    h2.win-type-ellipsis, .win-type-x-large.win-type-ellipsis {
        line-height: 1.3636;
    }
}

Technically speaking, the WinJS told me that this was not a breaking change, per se, because the media query for -ms-view-state: snapped no longer fires at all in Windows 8.1, so that chunk of CSS wasn't be used. This is why it was deemed dead code and removed altogether. Personally, I didn't understand why they didn't change the media query to detect a similar view, but it's easy enough to rectify manually. Just copy these styles into your own CSS and place them inside a media query for < 500px narrow views, if you support them. That is, replace the @media in the code above with this:

@media screen and (orientation: portrait) and (max-width: 499px)

 

 


Similar to last week’s two posts about simple thing that are easy to forget, we also have the fact that not all properties of HTML elements and not all CSS style properties can be animated with CSS animations and transitions (including WinJS.UI.executeTransition and similar helpers). For example, someone asked a question a while ago about some code that was attempting to animate an element’s scrollLeft property, but it wasn’t working. This is simply because scrollLeft isn’t an animatable property! In that case, the proper answer is to animate the desired motion using the transform property.

I have to say that I don’t know where a definitive list exists of what properties can or cannot be animated, but let me frame the question differently. When you use CSS animations or transitions on the transform and/or opacity properties, those animations will run “independently” in the GPU. Animating anything else–if it can be animated–runs “dependently” which means in the CPU and on the UI thread, which will typically perform poorly on less powerful devices. Similarly, you can always animate any property you want using requestAnimationFrame, but those always run on the UI thread as well.

The best practice, in short, is to always think how you can achieve the effect you want through transform and opacity. If you can’t, and must do a dependent animation, try it with CSS animations/transitions, and if that doesn’t work, then roll your own with requestAnimationFrame.


A while back I was working with a partner who asked what it would take to convert their web app (in HTML5 & CSS) into a great Windows Store app. This wasn’t a question of a minimal approach to just get it to work, but of making a really good app while still minimizing the work. I put together the following list of priorities with some general estimates of the amount of dev work involved. I figured this might be a helpful list for other developers.

For further inspiration, also check out the Website to apps topic in the design inspiration section of the Windows Developer Center.

Necessities:

  • Has to meet Store policies, which is some of what drives this list. (1-3 days) Key considerations:
    • 3.5: touch interaction must have visual feedback (meaning proper animations)
    • 3.6: handling view states and process management
    • 3.9: disallowing remote script
    • 4.1/4.1.1: privacy statement
    • 4.1.2: opt in for use of personal information
    • 4.5 Network cost awareness (especially for any large transfers) (.5-2 days)
    • 5.1 and 6.2: content and age rating
  • Explore a horizontally-oriented design (though vertical can be done especially with the Windows 8.1 ListView). (1-3 day design; dev is variable depending on the design and where you’re starting from)
  • View states: handle portrait, snapped, filled along with landscape. (2-3 days for design, implementation, testing) [For Windows 8.1 this means handling variable sizing rather than view states]
  • Handles resolution scales well, both display sizes and pixel scaling. (1-2 days)
  • Must run within the app container security boundary, which excludes remote script and script injection. (1 day to check; possibly more if things need to be rewritten)
  • Works with mouse, keyboard, and touch input, the latter of which means that touch targets need to be the right size. (.5 day design; 1-2 days dev)
  • Move chrome/commands off-canvas, generally (2 days design; 3-5 days dev)
    • Search to Search charm
    • Sharing functions to share source, though you may retain what you have as it’s integral to the experience
    • Settings to Settings charm including logins and profile management
    • Other commands and navigation to app bars
  • Handling suspend/terminate/restart and suspend/resume. (1 day)
  • Migrate from page navigation based on <a href> to single host page with DOM replacement (using page controls) (1-4 days depending on how you’re doing it now)
  • Great splash screen and branding graphics (1 day design mostly; .25 days dev)

Nice to Do:

  • Handling network connectivity or lack thereof (caching strategy/offline story) (2-4 days dev)
  • Live tiles: what can you surface on the tile? (1 day design; 2 days dev)
  • Roaming experience—what settings transfer to the user’s other devices? (1 day dev)
  • Globalization (making a world-ready, language-neutral app) (2 days dev)
  • Localization (1 day testing with pseudo-language; each language is likely an hour or less but needs to include time spent )
  • Accessibility (2 days)
  • Good use of progress indicators when transitioning pages. (.5 days design, .5 days dev)
  • Honing performance especially if using collection controls. (2-4 days day dev depending on goals)

 


In any discussion about animations, the GPU always comes up for good reason: anything that runs in the GPU will simply perform better in terms of UX and power consumption. If you hear the term “independent animation,” this refers to an animation that fully runs in the GPU. A “dependent animation” is one that runs on the UI thread.

In JavaScript, anything that you animate directly within setInterval, setTimeout, and requestAnimationFrame is a dependent animation, because you’re clearly doing all the work in code. This is unavoidable in many scenarios, like games, but then the point of the game is to play with graphics and animations so you’re not quite as worried about the GPU. It’s worth noting that at present, apps written in JavaScript don’t have access to the GPU outside of doing independent animations via CSS. Eventually I imagine that WebGL will become available which should change that story.

To run a CSS animation in the GPU, the key thing to remember is that you must be animating only the opacity and transform properties of an element. That’s it. You can actually do quite a bit with just these two properties: any kind of fades along with manipulations of size, 2D and 3D rotation, perspective, and so on. It just means that you need to be aware of how you and third-party libraries you might use define animations.

The animations library in WinJS.UI.Animation are all defined to be independent. The little bounce animation for a button click, pointerDown, for example, does a 97% scale transform, and its counterpart, pointerUp, restores the scale to 100%. You could, of course, achieve the same effect through the margin or padding properties, but then the animation would run in the UI thread.

In designing your dynamic UX, then, really become versed in what you can achieve with opacity and transform, and design around that. If, on occasion, you need dependent animations, that’s fine too. Just be careful to not overuse them to keep your app performing its best.


Wrapping up this series from part 3 we have two members of the WinJS.UI namespace that match others in WinJS.Utilites for obscurity.

The first is WinJS.UI.scopedSelect, to which you provide a CSS selector and an element. This function is documented as “Walks the DOM tree from the given element to the root of the document. Whenever a selector scope is encountered, this method performs a lookup within that scope for the specified selector string. The first matching element is returned.” What’s referred to here as a “selector scope” is a property called msParentSelectorScope, which WinJS sets on child elements of a fragment, page control, or binding template. In this way, you can do a querySelector within the scope of a page control, fragment, or template without having to start at the document level. The fact that it keeps going up toward the document root means that it will work with nested page controls or templates.

The other is WinJS.UI.getItemsFromRanges, which takes a WinJS.Binding.List and an array of ISelectionRange objects (with firstIndex and lastIndex properties). It then returns a promise whose results are an array of items in that data source for those ranges. Simply said, this exists to translate multiple selections in something like a ListView control into a flat array of selected items–and, in fact, is what’s used to implement the getItems method of a ListView’s selection property. So if you implement a list control of your own around a WinJS.Binding.List, you can use getItemsFromRanges to do the same. The method is provided, in other words, to work with the data source as that it a separate concern from the ListView itself.

 


Continuing from part 2 of this series, we’ll finish off the last few obscure methods of WinJS.Utilities. First, the empty method removes all child nodes from a specified element. This is basically a simple iteration over the element’s childNodes property, calling removeNode for each in turn (actually in reverse order). A simple bit of code, but one that you don’t need to write yourself.

Next is eventWithinElement. To this you provide an element and an eventArgs object as you received from some event. The method then checks to see if the eventArgs.relatedTarget element is contained within the element you provide. This basically says that an event occurred somewhere within that element, even if it’s not directly on that element. This is clearly useful for working with events on controls that contain some number of child elements.

Finally there’s getMember, to which you pass a string name of a “member” and a root object (defaults to global). The documentation says that this “Gets the leaf-level type or namespace specified by the name parameter.” What this means is that if you give it a name like “navigate” it will look within the namespace of the root you give for that member and return it. In the case of passing “WinJS” and “navigate” it will find WinJS.Navigation.navigate.

This is particularly useful with WinJS binding initializers that are given source and target property names as arrays of separate identifiers. For example, if I have a data-win-bind attribute with a property like title.style.color, the initializer will get an array with [“title”, “style”, “color”]. To either get or set that property for real, I need to turn it into the actual reference to the title.style.color property of the source of target object.

If I want to get that value from the source object, and the array of names is called “sourceProp,” I can do this: var value = WinJS.Utilities.getMember(sourceProp.join(“.”), source);

If I need to set a value in a target object with the array of named called targetProp, I need to pop the last name from the array, use getMember (if I have other names left), then reference the property with [], as in:

var lastProp = targetProp.pop();
var dest = targetProp.length ? WinJS.Utilities.getMember(targetProp,join(“.”), target) : target;
target[lastProp] = newValue;