Xamarin.Essentials.Interfaces released

Nestled amongst the impressive number of announcements related to Xamarin made during Microsoft Connect was the anticipated GA of Xamarin.Essentials. Since Essentials is no longer in preview, I've also moved my interfaces autogeneration experiment out of preview too, and outputs are being packaged up on NuGet for easy consumption. Xamarin.Essentials is designed to be no-bloat and doesn't ship with interfaces. Xamarin.Essentials.Interfaces - predictably - contains interfaces matching the Xamarin.Essentials API, for those that want them.

To use, you can Install-Package Xamarin.Essentials.Interfaces to get a set of interfaces and implementations that forward to the core library, useful for things like dependency injection and mocking.

What's in the box

The generated interfaces mirror the API surface of Xamarin.Essentials. As of 1.0.0 there are 29 interfaces generated:

  • IAccelerometer (3 members)
  • IAppInfo (6 members)
  • IBarometer (3 members)
  • IBattery (6 members)
  • IBrowser (4 members)
  • IClipboard (3 members)
  • ICompass (4 members)
  • IConnectivity (3 members)
  • IDeviceDisplay (3 members)
  • IDeviceInfo (8 members)
  • IEmail (3 members)
  • IFileSystem (3 members)
  • IFlashlight (2 members)
  • IGeocoding (3 members)
  • IGeolocation (4 members)
  • IGyroscope (3 members)
  • ILauncher (4 members)
  • IMagnetometer (3 members)
  • IMainThread (2 members)
  • IMap (6 members)
  • IOrientationSensor (3 members)
  • IPhoneDialer (1 members)
  • IPreferences (34 members)
  • ISecureStorage (4 members)
  • IShare (3 members)
  • ISms (2 members)
  • ITextToSpeech (3 members)
  • IVersionTracking (14 members)
  • IVibration (4 members).

Each of these has a matching implementation class (e.g. AccelerometerImplementation implements IAccelerometer) so can be registered individually if you prefer. For example,

using Xamarin.Essentials.Implementation;  
using Xamarin.Essentials.Interfaces;

builder.Register<IAccelerometer, AccelerometerImplementation>();  
builder.Register<IBattery, BatteryImplementation>();  

However, all implementation classes also implement IEssentialsImplementation, allowing for easy bulk registration. For example, in DryIoC:

// work out which types implement IEssentialsImplementation
var asm = typeof(IEssentialsImplementation).Assembly;  
var impls = asm.GetTypes()  
    .Where(t => typeof(IEssentialsImplementation).IsAssignableFrom(t) && t.IsClass);

// register them as implementations for their respective interfaces
foreach (var impl in impls)  
    foreach (var i in impl.GetImplementedInterfaces())
        builder.Register(i, impl, Reuse.Singleton);

When dynamically registering implementations - since you aren't directly referencing the implementation types - you will generally need to hint the linker to ensure they are included in your build. You can use falseflagging to do this.

When you want to mock, you can work with the individual interfaces as you would with any other interface:

// mock no placemarks 
var mockGeo = new Mock<IGeocoding>();  
mockGeo.Setup(x => x.GetPlacemarksAsync(It.IsAny<double>(), It.IsAny<double>()))  
       .ReturnsAsync(Enumerable.Empty<Placemark>());
// etc.
Releases

Xamarin.Essentials.Interfaces will drop in sync with the Xamarin.Essentials releases. If possible, version numbers will be consistent with those of the core library.

Happy mocking!