Cross-platform NuGet Packages

Xamarin Plugins are a special kind of NuGet package that let you easily add cross-platform functionality to your apps. Using NuGet to distribute Plugins means that anyone can create them, and of course consume them. The platforms supported by Plugins include Android, iOS, iOS Unified (64bit), Windows Phone 8, Windows Phone 8.1 RT and Windows Store.

Plugins abstract common device functionality or expose cross-platform APIs via a single interface

Plugins are small, have few or no dependencies, and provide a simple mechanism for accessing a single device function or feature. The following list represents some of the features you would expect to find on modern mobile devices.

  • GPS
  • Network Access
  • Battery Status
  • Vibration
  • Camera / Media
  • App cache
  • Speech-to-text

The aim of a Plugin is to expose one such feature using a singleton object (via an Interface) that hides the platform specific implementation on all platforms.

This approach in synonymous with using Inversion of Control (IoC) or Dependency Injection (DI) to invoke platform specific code from a shared project or a Portable Class Library (PCL).

Plugins Aren’t Components

… but they can be by following the Component creation and publishing guidelines.

A Xamarin Component gives developers the opportunity to distribute cross-platform libraries together in one neat package. When you add a Component to your Xamarin mobile project the correct platform implementation is automatically installed. Components are deployed by Xamarin and must be officially approved.

Plugins vs. Components

  • Components are normally used to offer cross-platform functionality at the UI level
  • Components typically integrate deeply into each platform they target

The above differences usually result in Components with diverging API implementations on each platform. As a consequence the use of the API becomes tightly coupled to each platform. In addition, very few Components target all of iOS, Android and Windows. Plugins, on the other hand, strive for a true cross-platform offering through one common API.

Plugin Development & Deployment

Plugins can be created by anyone and are a third-party driven part of the Xamarin ecosystem. Plugins do not need to be reviewed or approved by Xamarin.

In order to build a Plugin you will need Visual Studio and a business license of Xamarin (use a fully featured 30 day trial if you’re new to Xamarin). If you want to create and support your Plugins but have no intention to build and distribute apps, then you can apply for a special free license of Xamarin.

Publishing will require a NuGet user account. Alternatively an organisation can create an internal repository to host their cross-platform Plugins privately. However, if you do intend to contribute back to the Xamarin Community then ensure you publish your Plugin under an Open Source (OSS) friendly license like MIT.

Walkthrough

Many Plugins have already been published so definitely checkout the packages repository at nuget.org just in case your Plugin idea has already been developed. Alternatively you can view the Plugins offered in the Xamarin Component store.

Cross-platform “App Version” plugin

It’s common in almost every app to show the current version. Each platform uses a different approach for storing and retrieving this information, so abstracting this simple feature with a Plugin makes sense.

Quick Setup

  • Check your NuGet Package Manager is up to date. Ensure minimum version 2.8.3
  • Download and Install the Xamarin Plugin Template for Visual Studio
  • Create a project using the new Plugin template. The name of the solution needs to be simple because it will used throughout the Plugin code structure as a prefix and suffix for classes and file names.

ScreenShot1

With all projects created and initialized the screen shot below shows what your solution structure should resemble. Each platform being targeted has a corresponding project, with two additional portable (PCL) projects needed to complete the Plugin architecture.

ScreenShot2

The project called Version.Plugin.Abstractions is where we need to define the common API Interface. If you expand this project’s file structure you will see that an empty Interface has already been created for you by the template. For this walkthtough our interface is called IVersion.

At a minimum this Plugin needs to return the app’s version as a string, so we’ll add a getter property to our API.

///
/// Interface for Version
///
public interface IVersion
{
    ///
    /// Current App Version
    ///
    string Version { get; }
}

That’s it. With our simple API defined we just need to create concrete implementations for each targeted platform. When the template created each platform specific project, it added an implementation class with the name of your Plugin as the prefix.

IVersion for iOS implementation

// ./Version.Plugin.iOS/VersionImplementation.cs
public class VersionImplementation : IVersion
{
    readonly NSString _buildKey;
    readonly NSString _versionKey;

    public VersionImplementation()
    {
        _buildKey = new NSString("CFBundleVersion");
        _versionKey = new NSString("CFBundleShortVersionString");
    }

    ///
    /// Returns the app version with build number appended
    ///
    public string Version
    {
        get
        {
            var build = NSBundle.MainBundle.InfoDictionary.ValueForKey(_buildKey);
            var version = NSBundle.MainBundle.InfoDictionary.ValueForKey(_versionKey);
            return string.Format("{0}.{1}", version, build);
        }
    }
}

IVersion for Android implementation

// ./Version.Plugin.Android/VersionImplementation.cs
public class VersionImplementation : IVersion
{
    ///
    /// Returns the app version
    ///
    public string Version
    {
        get { return GetPackageVersion(); }
    }

    static string GetPackageVersion()
    {
        try
        {
            return Application.Context.PackageManager.GetPackageInfo(
                Application.Context.PackageName, PackageInfoFlags.MetaData).VersionName;
        }
        catch
        {
            return string.Empty;
        }
    }
}

The other platform implementations can be found in the sample code along with apps for testing each one.

CrossVersion Class

Using the API is the same on each platform. Example,

var version = CrossVersion.Current.Version;
Debug.WriteLine(version);

As you can see the name of the class that exposes the API has the Plugin name as a suffix. This is the standard naming convention for accessing all Xamarin Plugins. For example, a cross-platform Plugin for “battery status” would be accessed with a CrossBattery class.

The CrossVersion class is located in the PCL called Version.Plugin. You may have noticed this class file is also linked into all of the platform specific projects. This simple yet powerful class ensures the correct IVersion implementation is loaded at runtime because it’s compiled into each assembly.

public class CrossVersion
{
    static readonly Lazy Implementation = new Lazy(() =>
        #if PORTABLE
        null,
        #else
        new VersionImplementation(),
        #endif
        System.Threading.LazyThreadSafetyMode.PublicationOnly);

    public static IVersion Current
    {
        get
        {
            var version = Implementation.Value;
            if (version == null)
            {
                throw new NotImplementedException(
                    "Don't use CrossVersion from your PCL without first installing the NuGet package in your main project first.");
            }
            return version;
        }
    }
}

NuGet Deployment

Packaging

Download NuGet.exe and add it to your solution root folder. This executable will be used via the command prompt.

ScreenShot3

NuGet.exe needs a specifications file in order to package your assemblies correctly. Add a NuSpec file to the solution and fill in appropriate details. The Plugin template installed a new file type allowing you to add one with most of the details filled in.

ScreenShot4

ScreenShot5

Make sure you fill in these required fields,

  • id
  • version
  • title
  • owners
  • authors
  • license and project urls
  • descriptions

ScreenShot6

From a command prompt switch to the Plugin root folder. Set your NuGet account key, which can be found on your NuGet account profile page.

nuget setapikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Ensure your project configuration is in release mode and rebuild the solution. Then from the command prompt run the NuGet package command.

nuget pack Version.Plugin.nuspec

The output of this command is a NuPkg file with all of your Plugin assemblies packaged together.

ScreenShot7

Testing

Before releasing the package to the public you’ll need to test it throughly. The best way is to create a test app project and install the Plugin with the NuGet package manager. Via the package manager settings, add another source location for the package manager to search.

ScreenShot8

The source path will be the root folder of your Plugin.

ScreenShot9

Check the Plugin installs correctly and the implementation works as expected.

ScreenShot10

Publishing

Once you’ve fully tested the Plugin package, use the command prompt and your account key to publish.

nuget push Xam.Plugin.Version.1.0.0.0.nupkg xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Category:
Mobile
Tags:
, ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: