Dependency Service to NuGet package in Xamarin.Forms

Photo by Brunno Tozzo on Unsplash

Recently I wrote a post about how to create a project template so you can create your NuGets for Xamarin.Forms.
Now in this post, we are going to use this template to create our first package.
We are going to convert a dependency service from an earlier post step by step to a NuGet so we can reuse the service in any other project.
You will see how easy it is to create your packages and whats benefits are when you write code you can easily reuse.

The dependency service we are going to convert is reading the native screen dimensions for the different platforms.
If you don’t know what a dependency service is or just want to take a look at the service, check this post.

Prerequisites

To get started right away make sure you have the Xamarin.Forms NuGet template. Either create it or use mine (GitHub) and import it in Visual Studio.

Setup

So, let’s get started! 😀
At first fire up Visual Studio and create a new project using the Xamarin.Forms NuGet template. Name the project, like XamarinForms.Screen and click on create.
In the solution explorer, you can see the folder structure for the different platforms.

The difference between service and NuGet

To use platform-dependent code in Xamarin.Forms we use dependency services. Such service consists of mainly two parts.

  • The service interface
  • the native platform implementation

The interface will then be used in the shared code to specify what to expect from the native platforms. The dependency service in Xamarin.Forms know by the mean of the interface and platform the code is running on which native implementation he should call.
When we want to implement the same code in the NuGet we are going to use another coding principle called partial classes.

Partial classes

In the .net framework, a partial class is a class that can distribute their definition over multiple files located in the same namespace.
This means we can create multiple classes with the same name for different platforms.
The whole concept can be imagined in something like this:

  • You have one “main” implementation of the class (this is like the interface in dependency services)
  • Every platform that is supported by the package gets the same partial class with the native implementation

To get a better understanding of the concept head over to the code and get started 😉

Create the main class

As I said above we need to create a main class that defines the base structure of what we want to use.
The first step is to create a class called ScreenSize.cs in the “shared” folder of our project. This folder should contain all files that should be available on each platform.
In our example, we want to create a package to get the native screen dimensions. So we need at least two methods like this:

    /// <summary>
    /// get the native screen dimension of the current device
    /// </summary>
    public static partial class ScreenSize
    {
        /// <summary>
        /// get the native screen width
        /// </summary>
        /// <returns>the native screen width as double</returns>
        public static double GetScreenWidth() => GetNativeWidth();

        /// <summary>
        /// get the native screen height
        /// </summary>
        /// <returns>the native screen height as double</returns>
        public static double GetScreenHeight() => GetNativeHeight();
    }

In the above code, we implemented a static partial class with two functions to get the width and the height of the current device. We use the static modifier so we do not have to create an instance of the class every time we want to get the dimension.
The only task of these functions is to call the correct native code.
To write these native functions we create a new class in each of our platform folders.

The platform implementations

iOS

Let’s start with the iOS code.
To implement the native code to get the screen dimensions under iOS, create a new class called ScreenSize.ios.cs in the ios folder of your project.
Inside this class add the following code:

using UIKit;

namespace XamarinForms.Screen
{
    /// <summary>
    /// get the native screen dimension of the current device
    /// </summary>
    public static partial class ScreenSize
    {
        /// <summary>
        /// get screen width for ios devices
        /// </summary>
        /// <returns>the screen width as double</returns>
        static double GetNativeWidth() => UIScreen.MainScreen.Bounds.Height;

        /// <summary>
        /// get screen height for ios devices
        /// </summary>
        /// <returns>the screen heighr as double</returns>
        static double GetNativeHeight() => UIScreen.MainScreen.Bounds.Width;
    }
}

Important
When creating the platform-dependent classes make sure you are in the same namespace as the main partial class. Otherwise, visual studio will not be able to find the additional class definition.

The above code extends our definition of the partial class we have written before. If you would now go back to the main partial class and hover over a function definition you will see that visual studio can find the implementation for ios.

One platform done and only two left 😁

Android

We start again by creating the partial class (ScreenSize.android.cs). Remember to be in the same namespace!
The code for the native android implementation looks like this:

    /// <summary>
    /// get the native screen dimension of the current android device
    /// </summary>
    public static partial class ScreenSize
    {
        /// <summary>
        /// get screen width for android devices
        /// </summary>
        /// <returns>the screen width as double</returns>
        static double GetNativeWidth() => 
            Android.App.Application.Context.Resources.DisplayMetrics.HeightPixels / (double)Android.App.Application.Context.Resources.DisplayMetrics.Density;

        /// <summary>
        /// get screen height for android devices
        /// </summary>
        /// <returns>the screen heighr as double</returns>
        static double GetNativeHeight() =>
            Android.App.Application.Context.Resources.DisplayMetrics.WidthPixels / (double)Android.App.Application.Context.Resources.DisplayMetrics.Density;
    }

Save the class and go back to the main partial class and again hover over one of the native functions.
You should see that only the implementation of the standard framework is missing.

Tip
To see if your code has any errors in a specific framework version you can change the current framework view.

.netstandard

Last but not least we have to implement the partial class for the .netstandard framework. One or two will surely ask himself why we should do this? Well, this is because of the shared code basis in Xamari.Forms is based on .netstandard so to be able to implement the NuGet in the shared coded basis we need to do this.
Even if we have to implement the .netstandard framework this does not mean that the code should do something.
Our Xamarin.Forms app should only be running on either iOS or Android devices. So we will implement the .netstandard code to throw a not implemented exception because the code is not called anyway.

Just add another partial ScreenSize class in the standard folder (ScreenSize.standard.cs):

    /// <summary>
    /// not implemented for .netstandard
    /// </summary>
    public static partial class ScreenSize
    {
        static double GetNativeWidth() =>
            throw new NotImplementedException("This function is not implemented for .netstandard.");
        
        static double GetNativeHeight() =>
            throw new NotImplementedException("This function is not implemented for .netstandard.");
    }

When you have implemented the three platforms and the shared code you are as good as finished.
Although to create clean NuGet its recommended to set some metadata. This is important so that future users can immediately know what the package is about, who developed it, a project URL, etc.

Set some metadata

To set the metadata of the project right-click the project in the solution explorer. Then select “Package” and fill in the entries (especially the ones that say “FILL IN” 😉)

If you like to you can also change the package version number to match the current development status of your NuGet.

Build and Publish

Now you are ready to build and publish your NuGet for Xamarin.Forms! 😃
If you can remember, we’ve created two different property groups in the NuGet project template. One cares about the Debug and one about the Release configuration.
If you build the project in the Debug mode the project will create the corresponding .dll and .pdb files for every platform. If you want to create the NuGet package you have to build the project in Release.

Use the NuGet

Sooo, after you have built the project in release mode you are ready to use it! 💪
To use your package, you can upload it to a public NuGet server, like https://www.nuget.org/, or use it locally. 
To keep it simple, we create a local folder where we are going to store our package. Just create a folder where you put your NuGet in.

In the project where you want to use your NuGet right-click the project and select “Manage NuGet Packages…”. In the NuGet manager click on the gear icon in the upper right corner.

Create a new NuGet location with the plus button. Browse to your created folder click “Update” and “OK”.
If you now select your location under “Package source” you will find your NuGet. Just click on “Install” and you are ready to use your package.

Now you have just to head over to your code where you want to use your package.
Just use it like this:

// access your nuget 
var height = XamarinForms.Screen.ScreenSize.GetScreenHeight();
var width = XamarinForms.Screen.ScreenSize.GetScreenWidth();

Recap

As you have seen it’s super easy to create NuGets for Xamarin.Forms! The most important thing is to take care that each partial class you use is in the same namespace. Otherwise, visual studio will not be able to find the matching files.
That’s it!

It would be nice to see what NuGets you guys are creating to make Xamarin.Forms even greater 😃

As always the complete source code of this example can be found on GitHub.

Cheerio 😁😁

Leave a Reply

Your email address will not be published. Required fields are marked *