Microsoft announced a significant and dramatic convergence of its Windows 8.1 and Windows Phone 8.1 platforms during the Build 2014 conference. Approximately 90% of the WinRT APIs are now converged between the two platforms. Microsoft Visual Studio 2013 Update 2 includes features that enable developers to take advantage of this platform convergence. The Universal Apps project template is one of those features.
I will explain the structure of a Universal App and how code sharing is accomplished between the two platforms using the example of CensusMapper, a Windows 8 sample app I created last year. I have converted CensusMapper to a Universal App that now runs on both Windows Phone 8.1 and Windows 8.1, mostly built from the same code base.
A Universal App project contains a Shared project and two platform specific projects, one for Windows 8.1 and another one for Windows Phone 8.1. The shared project is compiled in the context of two platform projects. It does not have any binary output of its own.
A Universal App is not a single binary that executes on both platforms. You will still have two separate packages for the two platforms. A Shared project allows you to reuse most of your code and assets in both of those packages.
I have moved almost all the code that existed in the original Windows 8 app into the shared project. It includes code that represents the data as well as the classes that access Census and Bing APIs. Look closely and you will find two items that you were probably not expecting in the shared project, especially if you have written code for Portable Class Libraries:
- App.xaml and App.xaml.cs
The two platforms have been converged to the extent that even the Application Lifecycle and the Navigation Models have been consolidated. This allows App.xaml file to exist in the Shared project.
Inside App.xaml, you will find XAML ControlTemplates that I created to work as custom pushpins in the original WinRT app. The same XAML works as-is in the Windows Phone 8.1 app, this deserves applause. Windows and Phone platforms use the same XAML UI framework. Yes, you read that right. All the XAML UI is shareable between the two platforms. In many cases, you may want to customize the UI for different form factors, but as far as the runtime is concerned there is no difference between XAML for Phone and Desktop.
Note that the Windows Phone project does not reference any external libraries the way the Windows 8.1 project references the Bing Maps library. As it turned out, one of the things that has not converged between the two platforms is the Map control. Windows 8.1 is still using the Bing Map control but Windows Phone has already arrived in the future. The map control is built into the Windows Phone runtime under the Windows.UI.Xaml.Controls.Maps namespace. There are significant differences between the two controls and the APIs used to interact with them. I had to add platform specific code to account for these differences. The referenced article at the end of this post has more information on the two Map controls and the differences. The GeoPoint and BasicGeoPosition classes in the Windows Phone SDK can be used to convert to and from the Location class in the Bing Maps SDK. This works because the Windows.Devices.Geolocation namespace is available on both platforms.
It is also worth mentioning that the CensusMapper.Shared reference in the platform project is not a project reference. It is actually an MSBuid directive to include the Shared project’s contents while compiling the platform project. The code in the shared project automatically inherits the references in the platform project that includes it.
There are two ways for platform specific UI/code to exist in a Universal App project:
It can be in the shared project, compiled conditionally using the WINDOWS_APP and WINDOWS_PHONE_APP compiler directives. An example of this is the InsertContentTemplateAtLocation method in MainPage.xaml.cs file in the shared project.
It can exist in the platform specific projects and be assimilated using partial classes. The MainPage class is a partial class and it is compiled with one of the two counterparts in the context of compiling the Windows and the Windows Phone projects. The event handlers for the Tapped event on the Map control calls the AddPushPinAtLocation method which is defined in the partial class in the Shared project.
You can set the startup project to either the Windows Phone 8.1 or Windows 8.1 project directly from the debug target drop down:
CensusMapper is now a Universal App running on a Windows Surface 2 Pro tablet running Windows 8.1 and a Nokia Lumia 920 running Windows Phone 8.1.
The complete source code for CensusMapper Universal App is on GitHub: https://github.com/ashtewari/CensusMapper/tree/v1
You will need the following to compile and run the apps:
- Census API key: http://www.census.gov/developers/
- Bing Maps API key: http://www.microsoft.com/maps/create-a-bing-maps-key.aspx
- Bing Maps SDK: http://www.bing.com/dev/en-us/downloads
- Build Universal Windows apps that target Windows and Windows Phone : http://msdn.microsoft.com/en-us/library/windows/apps/dn609832.aspx
- Using Visual Studio to build Universal XAML Apps : http://blogs.msdn.com/b/visualstudio/archive/2014/04/14/using-visual-studio-to-build-universal-xaml-apps.aspx
- Windows Phone 8.1 for Developers–Maps : http://blogs.msdn.com/b/thunbrynt/archive/2014/04/22/windows-phone-8-1-for-developers-maps.aspx