Have you always wondered how Xamarin Forms does it’s “magic”? Knowing how things work under the hood is super valuable, especially when things go wrong. This enables you to detect the issue yourself, without having to rely on the knowledge of other developers. In this article a part of the magic of Xamarin Forms will be unraveled, as we take a look under the hood.
Xamarin.iOS and Xamarin.Android
Before we take a look at how Xamarin Forms actually works, you first have to understand how Xamarin.iOS and Xamarin.Android works. Xamarin Forms depends on these implementations.
I’m ignoring the other platforms like Windows Phone and Mac, to keep this article succinct.
Xamarin.iOS makes use of Mono to compile C# code into ARM assembly language, that can be used by your iOS devices. The native libraries and the compiled executable combined, form the IPA-file that can be uploaded to the App Store. Apple does not allow JIT (Just In Time) compilation, so it requires Xamarin apps to make use of AOT (Ahead of Time) compilation. There is a part of the app that runs on the Mono runtime, and makes use of bindings that call into the native (Objective-C) code and frameworks.
If you want an in depth explanation, I suggest you read the iOS architecture article on the Xamarin website.
Xamarin.Android also makes use of Mono, but it does not require you to do AOT compilation. Just like with Xamarin.iOS, a part of the app runs on the Mono runtime and also makes use of Android bindings to call the Android Runtime or Dalvik VM (depending on the Android version). This ultimately results in the APK-file, which is used to install the app and to upload to the Play Store.
If you want an in depth explanation, I suggest you read the Android architecture article on the Xamarin website.
These bindings in both platforms are the key to allowing C# code to use native libraries and frameworks. Xamarin supplies bindings whenever there is a new release of a platform. The Xamarin team starts working on these bindings as soon as beta versions of the SDK’s are released. So usually these bindings are available for developers before the SDK gets out of beta.
You can also create your own bindings for frameworks/jar-files, but I’ll leave that for another blog post.
For Xamarin Forms to work, you need platform specific projects, and a PCL or shared project that contains Forms specific code. The platform specific projects are the entry point for your app, and these call into your PCL or shared project. iOS has the AppDelegate and Android has the MainActivity to do so.
Forms supplies you with a lot of abstractions in the Xamarin.Forms package. These abstractions are classes with the common denominator of properties for controls that are available on each platform. For example: a Xamarin Forms button has properties to set the Text, BackgroundColor, TextColor, Font, and many others. But there are some things you can’t control through the properties supplied in the abstraction. For example, a button in Android always capitalises the text that it contains by default, and you have no way to disable that directly with a property on the Xamarin Forms class.
Xamarin Forms makes use of renderers that convert these abstractions into platform specific controls. These renderers build on the Xamarin.iOS and Xamarin.Android bindings that we talked about earlier. Take a look at all the available renderers for iOS and Android. The ActivityIndicatorRenderer is probably the easiest implementation of a renderer, so I suggest you take a look at that one first to prevent being overwhelmed. The ActivityIndicator is implemented as a UIKit.UIActivityIndicatorView on iOS, and a Android.Widget.ProgressBar on Android.
iOS renderer for the ActivityIndicator:
Android renderer for the ActivityIndicator:
If you take a look at these renderers, you can see they subclass the ViewRenderer class. The first generic argument is the abstraction supplied by Xamarin Forms, the second argument is the platform specific control. Such a ViewRenderer contains 2 important properties, being Control and Element. Control is the platform specific control, while Element gives you access to the Xamarin Forms abstraction properties.
These renderers are one of the cornerstones of how Xamarin Forms works, so some of them can be very complex to understand. To get a deeper understanding, I suggest you take a look at some of the provided renderers on Github.
Custom renderers & effects
When something is not available in Xamarin Forms, you can always create your own renderer. You can do this by subclassing an existing renderer, or make a completely new one by subclassing ViewRenderer. This means that everything that is possible with Xamarin.iOS or Xamarin.Android, is also possible in Xamarin Forms.
Effects work almost the same as a renderer, but are often easier to understand and implement. So if an effect does the job, use that to your advantage.
Embedding native controls
Since Xamarin Forms 2.2.0 and higher, you can embed native controls without using a renderer. This is easiest with a shared project, because you can use compiler directives to get to the native controls. If you only want to embed a native control in XAML, you can also use it in a PCL project, but you can no longer use XAML compilation if you do so.
The magic unraveled
So now you know that Xamarin Forms builds on what Xamarin.iOS and Xamarin.Android already offer by using bindings and the mono framework and runtime. You’ve also learned that the cornerstone of Xamarin Forms are the renderers that are provided by Xamarin.