Accessing Native Features with Xamarin.Forms

1. Setting the Stage

When it comes to writing mobile applications, it's important to integrate with the platform specific features that are available to you when it makes sense. For instance, if you were writing a navigation app, it would make sense for you to use the geolocation features of the device and platform. If you were creating an app to help people with a vision impairment, you would want to integrate with any text-to-speech features that were available as well.

It's the developers that take advantage of these features that set themselves and their apps apart from the rest. These simple things take just an ordinary app and make it great. But what happens when you want to take advantage of these features, but you have decided to adopt Xamarin.Forms as your cross-platform mechanism of choice? Do you have to give up hope on these features just because you decided that your app needs to be cross-platform and you want to be able to share as much logic and user interface code as possible? Absolutely not.

These types of questions inevitably cause some issues for developers that adopt newer technologies such as Xamarin.Forms. Prior to the release of Xamarin.Forms, when you were working directly with Xamarin.iOS, Xamarin.Android, and Windows Phone project templates, accessing these types of features was fairly straightforward. From the Xamarin perspective, if you could find sample C#—or even native language and SDK documentation—for a particular feature, you could simply map your code to the native concepts, because Xamarin did such a spectacular job of translating the same native concepts on those platforms into C# language constructs. Windows Phone features were even easier because there was no translation necessary. All you had to do was read the documentation.

Luckily for us as developers, Xamarin has put a lot of time and effort into designing a mechanism for us to access these same features even if we choose to use their Xamarin.Forms abstraction layer. This mechanism is know as the DependencyService.

2. DependencyService Overview

At first glance, a name like DependencyService may seem a little intimidating. It sounds like some fancy programming terminology that only the elite few understand. If you have ever worked with Dependency Injection (DI) or Inversion of Controller (IoC) containers, you should feel right at home with the DependencyService. If you haven't, I assure you that it is a very simple concept to understand once you break it down into its components.

What Is the DependencyService?

At it's most basic, DependencyService is a class. It's a class whose sole purpose of existence is to allow you to register any number of classes throughout your application. By register, I mean take any class you have and make it known to the service. Once the DependencyService knows about a class, it can go and retrieve an instance of that class whenever necessary. That is the other purpose of the DependencyService. If at any point in your application, you decide that you need an instance of a class that has been registered in the DependencyService, you can request or get an instance of it.

When you really get down into the nuts and bolts of the DependencyService, this is a very broad generalization. But from a developer's point of view, that's almost all you need to know. However, there is one other concept you need to be aware of when working with the DependencyService, interfaces. When it comes to the DependencyService and all of this registering and retrieving, you are typically doing that with respect to interfaces. This means that when you register a class, you are registering it as an implementation of a particular interface. And when you are retrieving a class, you are actually asking the DependencyService for an implementation of that interface. At this point, you don't really care what the implementation is, you just want a class that implements this interface.

How Does the DependencyService Work?

Now that you have a basic understanding at a conceptual level of what the DependencyService is, let's dig a little deeper and see how it actually works.

To use the DependencyService, you need three things:

  1. Interfaces: An interface is simply a construct that defines what members must be present within any class that chooses to implement, or agree, to this contract.
  2. Registration: Registration is merely the mechanism of letting the DependencyService know that a particular class wishes to be registered and be able to be retrieved later on.
  3. Location: This concept is often associated with a pattern in software development know as the Service Locator pattern. This simply means that you can go to a single place, the DependencyService, and request some functionality, a class, without having to directly instantiate a new instance.

Let's dig into each one of these concepts in a little more detail.

3. Interfaces

Interfaces are very common occurrences in most Object Oriented Programming (OOP) languages these days. Using an interface allows you to define a contract that contains a series of properties, methods, events, etc., that must be implemented by any class that agrees to that contract.

Here's a very simple example of an interface and a class that implements that interface.

This seems like a very simple example, but it serves the purpose quite well. The IFileGrabber interface defines a single method, GetFileContents. The SimpleGrabber class agrees to or implements the IFileGrabber interface, which means that it must contain an implementation for the one method.

Now, instead of having to implement other code in your application directly against a concrete class, SimpleGrabber, you can start to reference the IFileGrabber interface instead. Imagine you have another class in your application that looks like this:

By using the IFileGrabber interface instead of a concrete class, you have the ability to create other mechanisms to retrieve files from different places and the DataRetriever class wouldn't care. Let's assume we have another class that looks like this:

You now care less about how the class or the GetFileContents method is implemented, you just know that at least the members that are defined in the interface are present and that means you can continue to code away using just that interface as a reference. This is an incredibly important concept when it comes to the DependencyService.

4. Registration

In the context of the DependencyService, Xamarin has made the process of registering a class quite simple. Since you already have defined your interface and at least one class that implements it, you can register it in the DependencyService using a very simple assembly attribute.

Let's continue using the above example and register the SimpleGrabber class. The class definition would now looking something like this:

All you need to do is add the assembly reference above your class definition and outside of any namespace definition that may be contained within that file as well. By doing this simple task, you will have successfully registered the SimpleGrabber class as an implementation of the IFileGrabber interface.

When registering a class, that class must contain a parameterless constructor in order for the DependencyService to instantiate it. In my example above, I haven't defined a constructor so the compiler will, by default, create a parameterless constructor for me.

5. Location

The final piece of the puzzle is getting an instance of a registered class. This is actually the easiest part of the entire process. To retrieve an instance of a registered class, you simply use the DependencyService class and it's generic Get<>() method. Here's a simple example:

In this case, at runtime, you don't care where the DependencyService is getting the concrete class that implements the IFileGrabber interface. All you care about is that the class implements the IFileGrabber interface.

6. Using the DependencyService

Now that you have a conceptual understanding of what the DependencyService is and how to use it, let's create a simple application to put it to use.

For this example, I will be using Xamarin Studio 5, but feel free to use Visual Studio 2013 if you wish. Start by creating a new solution. In the New Solution dialog box, under the C# category on the left, select the Mobile Apps project family. On the right hand side, select either the Blank App (Xamarin.Forms Portable) or the Blank App (Xamarin.Forms Shared) project template. The code and the resulting application will be the same regardless of the template you choose.

In this example, I will be using the Portable Class Library (PCL) version of the template. Give a name to the project. I will be naming the solution and first project DependencyServiceSample. Then click the OK button.

This process will create three separate projects:

  • DependencyServiceSample - Shared library (PCL)
  • DependencyServiceSample.Android - Android project
  • DependencyServiceSample.iOS - iOS project

Xamarin Studio doesn't support creating Windows Phone projects. If you are using Visual Studio, this process will create four projects. It will create the above three projects as well as a Windows Phone project named DependencyServiceSample.WinPhone.

In the shared library (DependencyServiceSample), create a new interface file and name it ISampleInterface and give it the following implementation:

The is a standard looking interface file that defines a simple method named GetData that will return a string. Once again, the important point to understand is that from the perspective of the shared code file, it doesn't care what the implementation of this interface looks like. The only thing that matters is that whatever implementation is provided for this interface, it has a method named GetData that will return a string.

Next, we modify the App.cs file to use the DependencyService to get an instance of the ISampleInterface to use in your Xamarin.Forms app. Modify the  GetMainPage method to look like the following:

Notice that the only difference is that the Text property of the Label has been changed to the following line:

This way, you are using the DependencyService class and the generic Get<>() method to retrieve whatever implementation of the ISampleInterface is implemented in the platform specific project that is currently running. Once that instance has been retrieved, you are calling the GetData method to get back a string and set the Text property of the Label.

The last step has two parts (three if you are using Visual Studio). At this point, you will need to implement the ISampleInterface interface in all of the platform specific projects in your solution.

Let's start in the DependencyServiceSample.Android application. All you need to do is create a new class file in the project and give it any name you like. I have named mine Sample_Android. Replace the default implementation with the following:

This is a simple class that implements the ISampleInterface interface and its implementation is to simply return a string stating that it's coming from the Android project. The only difference is the use of the assembly attribute at the top of the file that registers this class with the DependencyService so that it can be retrieved later.

Now, let's create another implementation of this interface in the iOS project. Create a new class in the iOS project, name it Sample_iOS, and replace the default implementation with the following:

The implementation is exactly the same as the Android version, except that it returns a different string stating that it's coming from the iOS project this time. The final step is to run the application and see if you are getting the result you are expecting.

Here is the result of the iOS application running.

  

Here is the result of the Android application running.

As you can see, both applications run successfully. Not only do they run, but they are successfully running from a shared Xamarin.Forms project that is controlling the user interface. From that user interface code within Xamarin.Forms, you are now able to dip directly into the platform specific projects to access native code.

7. Where to Go From Here

Now that you have the skills to use the DependencyService to get access to native functionality from Xamarin.Forms, the sky's the limit. You can continue to write simple implementations as you have done in this tutorial or you can start to tap into more interesting features of the platforms.

One of the most interesting resources to take a look at for integrating into your DependencyService is the Recipes section of the Xamarin website. Here you'll find platform specific implementations of getting access to a number of features including:

  • Networking
  • Audio
  • Video
  • Geolocation
  • Accelerometers

All of these features are at your disposal when it comes to Xamarin.Forms applications. With the DependencyService, these features can be summoned at a moment's notice.

Conclusion

Now that you know and understand the DependencyService, you no longer have to feel intimidated when you need to access platform specific features from a Xamarin.Forms application. You now possess the tools that allow you to tap into those amazing native features of the devices that will ultimately allow you to differentiate your apps from the rest in the app stores.

Next Step: Watch the Course

If you'd like to learn more about Xamarin, then check out our course Building Multi-Platform Apps With C# in Xamarin

In the course, you will learn how to create a cross-platform application from a single code base that will run on three distinctly different platforms: iOS, Android, and Windows Phone 8. Think it can’t be done? In just a little while you will be doing it yourself. Let’s get to work.

You can take the straight away with a completely free 14 day trial of a Tuts+ subscription. Take a look at our subscription options to get started or, if you're just interested in this course, you can buy it individually for $15! Here's a preview to get you started:

Tags:

Comments

Related Articles