2 Comments

Image of an escalator going towards the light

This post is part of the Xamarin Month, which is about community and love. Looking after a nice UI and User Experience is one way how a product team or developer can show love to its user. So let focus on a small detail which always makes me smile when done right 🙂

Xamarin Forms apps have a reputation for taking their time to load. While quicker loading times are always preferred and are an excellent place to start. Sometimes there is no way around letting the user wait, while a background process is doing it's best to do its task. However, there is an alternative to speed: Distraction. Distraction is what Airplanes do with their onboard entertainment, and it is what some apps like Twitter do on startup with an animated logo. Since Xamarin Apps fall into the latter category, let's see how we can improve our startup experience with some fancy animated Xamarin Hexagon.

However, before we get started with the animation part, I'm afraid we have to take a quick look into one of our platform projects - into the Android project that is.

The empty feeling when starting Xamarin.Forms on Android

Have you ever wondered why the startup screen experience of your Xamarin app on Android differs from iOS or UWP? While we are greeted instantly with a logo when starting up our Xamarin.iOS app, when starting the same app on Android, a blank screen stares at us. Why is that so?

Screenshot_1550416214

Just point it out: this is not the fault of Xamarin Forms, it is more a difference in the two platforms. While iOS forces you to provide a startup storyboard (a single view), there is no such thing under Android. At least that may seem so at first. However, from where is this blank screen? You probably already know that the starting point of a Xamarin.Forms app on Android is the MainActivity.cs or to be more precise that one activity which has the following attribute set:

[Activity( ... Theme = "@style/MainTheme", MainLauncher = true, ... ]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
	// ...
}

One attribute that is getting set is the theme. This theme is where Android "draws it's inspiration" for the splash screen. We can find it defined under Resources\values\styles.xml. Now to replicate the startup image, we first have to define a layout in Resources\drawables\splash_screen.xml along the following lines:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <color android:color="@color/colorPrimary"/>
  </item>
  <item>
    <bitmap
        android:src="@drawable/SplashScreen"
        android:tileMode="disabled"
        android:gravity="center" />
  </item>
</layer-list>

Now we can modify styles.xml by adding new style with the following lines:

<?xml version="1.0" encoding="utf-8" ?>
<resources>

  <!-- ... -->

  <style name="SplashTheme" parent ="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowFullscreen">true</item>
  </style>
</resources>

Starting the app and we see the Xamarin logo while starting up. Unfortunately, it does not go away when we get to our Hello World page in Xamarin Forms. The reason being that we have overwritten the default style which is also used by our Xamarin.Forms app. However, we can fix this by adding an activity solely to display this new style, once the new SplashActivity.cs is rendered we switch over to the current MainActivity.cs. The MainActivity.cs uses the original style and starts the Xamarin.Forms part of our app.

Screenshot_1550416896

If we let the app run the app now. We do see a splash screen which disappears after starting up the app. So now that we have Android on par with iOS and UWP let's shift gears and implement that bouncy startup animation.

Bouncy startup animation

Drawing some inspiration from the Twitter app, let's let our logo bounce similarly. We implement the animation of the hexagon in Xamarin.Forms. The animation could - in a real app - buy us some time while we are starting up. So what we need is again a splash screen but this time a Xamarin.Forms view. The XAML displays an image in the centre:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomSplash.SplashPage"
             BackgroundColor="#2196F3">
    <ContentPage.Content>
        <Grid>
            <Image x:Name="SplashIcon"
                   HorizontalOptions="Center"
                   VerticalOptions="Center"
                   Source="SplashScreen.png" />
        </Grid>
    </ContentPage.Content>
</ContentPage>

The XAML is ready. However, this would solely extend the static native splash screens. The animation takes place in the code behind. We can override the OnAppearing method and add some animation logic to it:

await SplashIcon.ScaleTo(0.5, 500, Easing.CubicInOut);
var animationTasks = new[]{
    SplashIcon.ScaleTo(100.0, 1000, Easing.CubicInOut),
    SplashIcon.FadeTo(0, 700, Easing.CubicInOut)
};
await Task.WhenAll(animationTasks);

First, we shrink the image, then we expand and simultaneously let it go transparent. Combining the animations gives our app a nice fluid effect. While we could now put this puppy in a loop and endeavour it forever and ever and ever and... well most probably we only want to show it once and then move on to our main page. The following lines achieve this:

Navigation.InsertPageBefore(new MainPage(), Navigation.NavigationStack[0]);
await Navigation.PopToRootAsync(false);

The above lines insert the main page as the first page in the navigation stack. In other words, we insert the main page before the splash screen. Then we PopToRoot so the splash screen is no longer present on the navigation. So while the lines might look a bit odd at first. They prevent the user from navigating back to the splash page. Further, it allows the splash page to be garbage collected. Bottom line all the things we want to do with a splash screen once it has served its purpose.

The resulting app looks something like this:

Animation splash screen on iOS

I am a firm believer that these little things can go a long way and show your user right from the get-go that you care about your app. While the native splash screen is a good start. The animated load screen can buy you a bit of extra time to start up your app while distracting the user. You can find the entire demo app on GitHub.

Be sure to check out the other blog posts in the Xamarin Universe and happy coding!

0 Comments

pexels-photo-64774

Update: Hey there thank you for reading my blog, since I wrote this post I have learnt a lot and have found a better way to migrate your Xamarin Apps so please check out my latest blogpost on this matter.

If you haven’t heard or dived into .Net Standard you are in for a treat. In short it provides a way to share code across platforms but in contrast to the PCL it gives you so many more platform specific features. For an in depth overview check out the official docs.

Note: If you are starting a new Project today with Visual Studio (VS) 2015.4, you will not be able to select .Net Standard by default. But the new templates for .Net Standard will be included in Visual Studio 15.5.

Creating the .Net Standard Class Library

Migrating an existing app to .Net Standard is pretty straight forward. Step one add a .Net Standard Library to replace your PCL project.

The VS Add New Project dialog, under Visual C# select Class Library (.Net Standard)

Migrating your source code

Then drag and drop all of your existing files from the PCL project to your .Net Standard library. Note that you don’t want to copy the packages.config or any of the files under properties.

CopyFiles

Now you can delete your PCL project that you have migrated. If you do so from Visual Studio note that the Project is still available in the file system. Which means you still have it if you forgot something, but also means that you will have to delete it later on if you want to remove it from the source control workspace.

Next step is to add all the NuGet packages you have used in the PCL project. If you are having trouble adding some of the packages look out for NuGet packages that are no longer needed due to .Net Standard support such as file system access. In other cases it could be because the NuGet package has not (hopefully yet) migrated to .Net Standard. In that case check out this post and don’t forget to ask the maintainers of the project when the project will be available for .Net Standard Winking smile

Hooking up the projects

You can now add the reference to the .Net Standard in your Android and iOS project. If you created a new namespace I strongly recommend you refactor them after adding them to your projects. Or else your refactoring tool of choice will only do half the magic and you will still have some work left to do.

If you are using a UWP project please read the section bellow as you will need to make some additional steps to make it work.

Fixing the csproj for Xamarin Forms

Unfortunately when moving a Xamarin Forms app over to .Net Standard you will get weird compilation errors. The cause of this is that the XAML files are referenced in the csproj file:

02_1_RemoveEmbeddedResources

Simply remove them as they are not needed and the compile errors should be history.

When using UWP

If you are using UWP as a target (I.e. using the default Project provided up to VS 2015.4). You will have to remove and add the project anew:

If you are unsure if you really have to update your UWP project. Check if you have a project.json file in your UWP project. If the answer is yes, I’m afraid you will have to follow the following steps.

  1. Remove the UWP project from the solution in Visual Studio
  2. Rename the UWP project folder in the file explorer
  3. Add a new UWP project in Visual Studio (with the same name as the one just removed)
  4. Set the minimal supported Windows 10 version to the Fall creators update

    VS Dialog Window with Target and Minimum Version set to Fall Creators Update
  5. Add any NuGet references the just removed project had (you can peek into the project.json file in the renamed location if you are unsure which packages to add)
  6. Copy and paste all your UWP files (except the project.json)
  7. Add a reference to the Standard Library project

If you know an easier way to upgrade a UWP project, please let me know in the comments bellow Smile

Conclusion

In this post we went over the steps required to migrate an existing PCL project to .Net Standard. All the steps were done with Visual Studio 15.4.

0 Comments

Overview of UWP Apps Platforms

With UWP apps it has become easier then ever to write a single app that will run natively on all Windows 10 devices be it a phone, tablet, PC, Xbox et. al. Now we don’t just want our apps to be able to run on a device we want them to shine while they are running. In this blog post we will look at the basics on how to adopt to different screen sizes within your UWP app.

 

The devices and screen sizes

UWP runs on many different platforms some might not even come with a screen by default e.g. Internet of Things (IoT) devices or others that require a unique UI such as HoloLens which should be available for a few lucky developers later this year. Now while those platforms are very interesting in certain scenarios a wide array of apps will most probably be developed for mobile devices such as phones, tablets and phablets aka BAPHs (Big a** Phones). The unique thing about the UWPs in comparison to Android and iOS apps is that you apps will not only run on mobile devices but on desktop machines, laptops and even larger screens such as the new Surface Hub.

Windows 10 Devices
Now write once run everywhere and look like crap is easy to do. But the great benefit of creating a UWP app is that you can adopt to the different screen sizes and even adopt to different user input such as touch vs mouse and keyboard. But before we dive into the details of how we can write responsive UIs with XAML lets have a look at some basic layout rules.

Devices and screen sizes

A general split up of the devices can be made as follows.

CategoryScreen sizeWidth in Effective PixelsInputs
Phone4” to 6”340+Touch & Voice
Phablet6+” to 7”720+Touch & Voice
Tablet7” to 13.3”1024+Toch, Stylus, External keyboard*, Mouse*, Voice*
PCs and Laptops13” and greater1024+Mouse, Keyboard, Touch*, Gamepads
Surface Hub Devices55” and 84”1024+Touch, Pen, Voice, Keyboard, remote Touchpad

*: occasionally

Basic layout guides

Since UWP apps are built from the ground up to run on all kinds of different devices i.e. form factors the platform comes with many helpers that make life easier to design for multiple platforms. One basic concept are effective pixels. Effective pixels differ from actual physical pixels so 24 effective pixels on a phone will scale up to a larger physical appearance on a larger screen. The scaling of effective to physical pixels is all done by the framework and does not require any special attendance by the developer i.e. designer.

Image showing the diferent scale factors accroding to the device.

Note: Often small screens do have very large Dots Per Inch (DPI), this is also handled by the platform so even if you are running on a small device with a cheap display i.e. low DPI the text will still be readable as clearly as on a higher end display with more pixels i.e. a higher DPI.

The scaling is based on multiple of fours (4), so when defining layouts make sure they are a multiple of four e.g. 16. This will ensure that the scaling will not lead to strange effects. When using icons, rather than using images try to use a font (for example the new Segoe MDL2 Assets) that provides the icon you are looking for (or close enough). Though Windows 10 does provide a mechanism that chooses between different resolutions of an image according to the screen size, a font will always scale without any further effort.

Implementing responsive layouts that adapt to the available screen space

When working with different resolutions there are multiple layout adjustments that can be performed to improve general User Experience (UX) and – Interaction. UWP offer a variety of ways to adjust the layout of an app according to the available screen space.

  1. Changing layout of elements on a page according to form factor and available screen space
  2. Reflow e.g. adding text columns when the screen size increases
  3. Reveal information/functionality depending on the device and it’s resolution
  4. Replace elements such as navigation bars with fly out menus to accommodate smaller screen estate
  5. Change screen flow e.g. of master detail sites

So lets dive into how we can change the layout of UI elements according to the screen space.

Responsive Layout

ResponsiveDesign

One new feature of UWP apps is the possibility to adapt the layout of the controls according the available screen size i.e. the effective pixels width of the app windows. This lets the UI adapt to different screen sizes e.g. phones and tablets but also lets the UI adapt to the size a Window has on a desktop.

Lets assume you have the following screen flow and layout in your app:

Shows app running with fewer than 720 effective pixels.

The basic Layout of the app looks as follows:

<RelativePanel>
    <Rectangle x:Name="Image" Width="80" Height="80" Fill="Gray" Margin="8"></Rectangle>
    <Rectangle x:Name="TextLine1" Height="16" Width="200" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="" Margin="8,8,8,4"/>
    <Rectangle x:Name="TextLine2" Height="16" Width="200" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="TextLine1" RelativePanel.AlignLeftWith="TextLine1" Margin="8,8,8,4"/>
    <Rectangle x:Name="TextLine3" Height="16" Width="168" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="TextLine2" RelativePanel.AlignLeftWith="TextLine1" Margin="8,8,32,4"></Rectangle>
</RelativePanel>

Note: that rendering the items in a RelativePanel allows the elements within i.e. the Rectangle to align themselves relative to one another. This is a new layout feature available in Windows 10 UWP apps which previously had to be done with a Grid or StackPanel. The benefit of using relative layouts is when we focus on how we might want to realign the content for a different screen(size).

For instance when displayed on a tablet you might not just want to show a small image next to the text but go with a banner. Using a VisualStateManagerone can easily define trigger points for the minimal window Width and  if the trigger fires adopt the layout of the predefined layout:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="wideView">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="720" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="Image.(Width)" Value="720"/>
                <Setter Target="TextLine1.(Width)" Value="720"/>
                <Setter Target="TextLine2.(Width)" Value="720"/>
                <Setter Target="TextLine3.(Width)" Value="600"/>
                <Setter Target="TextLine1.(RelativePanel.Below)" Value="Image"/>
                <Setter Target="TextLine1.(RelativePanel.AlignLeftWith)" Value="Image"/>
            </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="narrowView">
            <VisualState.Setters>
                <!-- Adjust view for narrow view -->
            </VisualState.Setters>
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0" />
            </VisualState.StateTriggers>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

The name of the Target matches the x:Name given to the controls. The page will now re-render if the app has more then 720 effective pixels:

Shows app running with more than 720 effective pixels.

The page will also adjust when resizing the window on a Windows 10 desktop machine which allows the user to have multiple applications open at once with them seamlessly adapting to new windows sizes.

Conclusion

In this post we saw that Universal Windows Platform Apps not only run on multiple devices but that the platform provides the developers and designers with the necessary tooling of creating a great User Experience no matter the screen size and resolution without having to create multiple page layouts from the ground up and having to somehow figure out the size of the screen itself.

You can find the entire project on GitHub.

0 Comments

nuget

See how you can easily create NuGet packages to publish cross platform C# libraries that allow to integrate platform specific code in your Portable Class Library (PCL) based Projects. In a former post you can read about how to create a cross platform library and see how the library has to be consumed by the e.g. app consuming the library. This post builds up on where that last post left off and shows how we can use the library providing the OS version number in a NuGet package. So the package we want to create has the following structure:

 

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

 

Our goal is to generate a single NuGet package which can be added to any of the above named platforms.

Note: Though this post focuses on the platforms Universal Windows Platform (UWP), Android and iOS the approach can be easily extended to support additional platforms such as .Net, Silverlight et al.

Creating the package definition

First of all we will need to install the NuGet command line tool. Make sure that you add it to your PATH. After it is added to your path you can execute the NuGet commands with PowerShell. To create a NuGet package you need a nuspec file which you can generate by executing the command):

nuget spec

The location of the nuspec file does not really matter – I tend to have it in my root directory i.e. where the Solution file is. If you open the file in your lightweight editor of choice, you can edit the package specification to your gusto or for our sample somewhat like this:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>OSVersion</id>
    <version>1.0.0.3</version>
    <title>OS Version</title>
    <authors>Mark Allibone</authors>
    <owners>Mark Allibone</owners>
    <!--<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>-->
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Get the OS version for your UWP, Android or iOS app.</description>
    <releaseNotes>This is the initial release.</releaseNotes>
    <copyright>Copyright 2015</copyright>
    <tags>OSVersion</tags>
  </metadata>
  
  <files>
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.dll" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.pdb" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.xml" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.dll" target="lib\UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.pdb" target="lib\UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.xml" target="lib\UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.dll" target="lib\monoandroid1\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.pdb" target="lib\monoandroid1\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.xml" target="lib\monoandroid1\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.dll" target="lib\xamarin.ios10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.pdb" target="lib\xamarin.ios10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.xml" target="lib\xamarin.ios10\OsVersionAPI.Core.xml" />
  </files>
</package>

Beware of the target folder structure, these names may seem a bit strange (I’m looking at you Xamarin.Android…) but these actually have to align with a pattern or else you will run into problems when installing the NuGet package. You can find the target folder names on the NuGet website.

Integrating some Metadata in the NuGet package

You are not required to add the pdb (used for Debugging) or the XML file (Code Documentation for Intellisense) but it is considered best practice and makes the life of the developer using the library easier so I would suggest you follow along with this.

To enable the XML metadata file, right click on a project under Properties, Build you can set the checkmark for XML documentation file. Now you should have an XML file in your build output.

Per default the pdb file should be generated during the build, except for iOS (it’s always you iOS isn’t it…) - anyhow, right click on your project then under Properties, Build, Advanced… set Debug Info to pdb-only.

Beware that these settings are per build Configuration so make sure you set it for Release builds as you usually ship the Release build of a library.

Packing it up

Now all that is left to do is creating the package which we can do with the following command:

nuget pack

After the package is created the next thing to do is make it available for consumption. This means either pushing the package to NuGet or creating your own NuGet repository. Due to the fact, that this here is only a demo I will go with the second option.

Integrating the package in an app

Now we can simply add the OS Version library over the package manager. Notice that we get the same result as in the former blog post but this time the developer using the library will not be required to add the library multiple times to the project i.e. this potential error source no longer exists.

So when we now run the app under UWP we get the following output.

Win10VersionNumber

Note if we would only add the NuGet package to the NativePcl.Core project the output would simply show the stub implementation.

StubVersionNumber

So all the principals that were described in the last post still apply. But adding the library has been greatly simplified.

Conclusion

In this blog post you saw how a cross platform NuGet package can be created which lends itself very well to create cross platform libraries that implement native features which have to implemented differently for each targeted platform. There are many great libraries already out in the wild that use this approach e.g. MVVM Light, SQLite, PCL Storage and many many more.

You can find the sample project on GitHub.

0 Comments

See how you can offer cross platform APIs based on C# that you can consume in Universal Windows Platform Apps (UWP), Xamarin.iOS, Xamarin.Android, Xamarin.Forms, ASP.Net and even your classic .Net WPF app. In my last post I showed how one can use platform specific libraries and code in a Portable Class Library with dependency injection. This approach is great when you are developing your own app but it gets somewhat quirky, when you want to offer a library to fellow co-workers/developers, as you force them to setup your own library through dependency injection. But there is of course another way that allows you to encapsulate your implementation details neatly while still providing platform specific features to your PCL code.

The library in this blog post will provide the OS version for a UWP, Xamarin.iOS and Xamarin.Android app.

Setting up the library

The library consists of four projects:

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

One thing which is a bit special about all the projects is that all of their Default Namespace and the Assembly name all have the same name.

NamespaceBinaryName

In each project we implement the SystemInformationHandler.cs class, on the PCL we simply implement a stub:

public class SystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    public static string OSVersion => "Gnabber";

    #endregion
}

For the other platforms such as UWP we implement the calls to the UWP specific APIs:

public class SystemInformationHandler
{
    public static string OSVersion
    {
        get { return OsVersionString(); }
    }

    private static string OsVersionString()
    {
        string sv = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
        ulong v = ulong.Parse(sv);
        ulong v1 = (v & 0xFFFF000000000000L) >> 48;
        ulong v2 = (v & 0x0000FFFF00000000L) >> 32;
        ulong v3 = (v & 0x00000000FFFF0000L) >> 16;
        ulong v4 = (v & 0x000000000000FFFFL);

        return $"Windows {v1}.{v2}.{v3}.{v4}";
    }
}

So in the end we have implemented the generic class in the PCL and specific classes for each platform we target to support. Now lets see how we can consume this library in an app.

Consuming the library

The app will exist of the usual cross platform mobile app setup which means we will have usual suspects covering Windows, Android and iOS with a Portable Class Library aka Core to share the reusable code.

NativePclProjectOverview

In the core we have our business logic code and view models (I’m a huge fan of the MVVM Light library, to find out more just view my mvvm light posts). In the NativePcl.Core project we have a service OsVersionService.cs for returning the version number:

public class OsVersionService : IOsVersionService
{
    public string GetVersion()
    {
        return SystemInformationHandler.OSVersion;
    }
}

Reference the OSVersion.Core library as binary – DO NOT reference it as project or you will be facing compile errors in one of the next steps. Don’t ask me how I know Winking smile

Because all our assemblies of the OSVersion library will be compiled to assemblies with the same name we can’t just simply reference the project file but have to add the binary i.e. the compiled version of the library. If you are looking at the sample from GitHub, make sure to compile the solution under release build as the OSVersion is referenced via binary in the release output folder of the projects.

The method invokes the OSVersion property in the OSVersion library - leaving out the specific project e.g. UWP intent fully here. On the clients for example the Android app we have a single screen showing the version number defined in the MainView.xaml:

<Page
    x:Class="NativePcl.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NativePcl.UWP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

And the corresponding code behind or as we are using view models MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    private readonly IOsVersionService _osVersionService;

    public MainViewModel(IOsVersionService osVersionService)
    {
        if (osVersionService == null) throw new ArgumentNullException(nameof(osVersionService));
        _osVersionService = osVersionService;
    }

    public string OSVersion => _osVersionService.GetVersion();
}

If we now run the app we will get the follow output:

coreVersion

Now this is the output we defined in the OSVersion.Core, if we now reference the binary of the OSVersion.UWP in the NativePcl.UWP project things get really interesting. Instead of receiving an error because we are adding two assemblies with the same name the compiler will prefer the platform specific library over the PCL implementation. And even though we never invoke the library directly from our NativePcl.UWP app the OS version returned now is returned from the platform specific i.e. OSVersion.UWP implementation of the GetVersion() method resulting in the following output:

uwpVersion

Now while this approach allows for writing platform independent logic in the PCL and calling platform specific implementations during runtime it is somewhat tedious as it requires that the developer will reference the correct version of the library. And all of them have the same name which is just calling for some frustrated minutes to happen due to referencing the wrong version of the library. Luckily there is a technique that allows to use the approach described above without burdening the developer consuming the library of referencing the binaries correctly. By wrapping the library in a NuGet package consuming the library is as simple as adding the package to all of your projects and the NuGet package manager will just like the build engine prefer to link the platform specific binary over the PCL library to the project. So instead of having to choose which binary to add the developer can now simply add the identical NuGet package to all of the projects and it will just work.

Conclusion

In this post you saw how to create APIs that can be consumed in the PCL and still provide platform specific functionality. For all of this to work we had to set the namespace and assembly of the projects to identical names. On the consumer one can either simply add a NuGet package containing all of the implementations i.e. PCL, UWP, Android and iOS or add the binaries of the corresponding API compilation to the app implementation e.g. OSVersion.Coreto NativePcl.Core.

This approach allows you to create APIs which can be reused across multiple platforms providing the same method definitions across the platforms.

You can find the sample on GitHub. (make sure to compile it first as a release build)