This chapter is all about getting to know Xamarin and what to expect from it. It is the only chapter that is pure theory; all the others cover hands-on projects. You are not expected to write any code at this point, but instead, simply read through this chapter to develop a high-level understanding of what Xamarin is and how Xamarin.Forms relates to Xamarin and how to set up a development machine.
We will start by defining what a native app is and what .NET as a technology brings to the table. After that, we will look at how Xamarin.Forms fits into the bigger picture and learn when it is appropriate to use the traditional Xamarin and Xamarin.Forms apps. We often use the term traditional Xamarin to describe apps that don't use Xamarin.Forms, even though Xamarin.Forms apps are bootstrapped through a traditional Xamarin app.
In this chapter, we will cover the following topics:
- Native applications
- Xamarin and Mono
- Setting up a development machine
Let's get started!
The term native application means different things to different people. For some people, it is an app that is developed using the tools specified by the creator of the platform, such as an app developed for iOS with Objective-C or Swift, an Android app developed with Java or Kotlin, or a Windows app developed with .NET. Others use the term native application to refer to apps that are compiled into machine code that is native. In this book, we will define a native application as one that has a native UI, performance, and API access. The following list explains these three concepts in greater detail:
- Native UI: Apps built with Xamarin use the standard controls for each platform. This means, for example, that an iOS app built with Xamarin will look and behave as an iOS user would expect and an Android app built with Xamarin will look and behave as an Android user would expect.
- Native performance: Apps built with Xamarin are compiled for native performance and can use platform-specific hardware acceleration.
- Native API access: Native API access means that apps built with Xamarin can use everything that the target platforms and devices offer to developers.
Xamarin and Mono
Xamarin is a developer platform that is used to develop native applications for iOS (Xamarin.iOS), Android (Xamarin.Android), and macOS (Xamarin.Mac). It is technically a binding layer on top of these platforms. Binding to platform APIs enables .NET developers to use C# (and F#) to develop native applications with the full capacity of each platform. The C# APIs we use when we develop apps with Xamarin are more or less identical to the platform APIs, but they are .NETified. For example, APIs are often customized to follow .NET naming conventions and the Android set and get methods are often replaced by properties. The reason for this is that APIs should be easier to use for .NET developers.
Mono (https://www.mono-project.com) is an open source implementation of the Microsoft .NET framework, which is based on the European Computer Manufacturers Association (ECMA) standards for C# and the Common Language Runtime (CLR). Mono was created to bring the .NET framework to platforms other than Windows. It is part of the .NET Foundation (http://www.dotnetfoundation.org), an independent organization that supports open development and collaboration involving the .NET ecosystem.
With a combination of the Xamarin platforms and Mono, we can use both the platform-specific APIs and the platform-independent parts of .NET, including namespaces, systems, System.Linq, System.IO, System.Net, and System.Threading.Tasks.
There are several reasons for using Xamarin for mobile app development, which we will cover in the following sections.
If we use one common programming language for multiple mobile platforms (and even server platforms), then we can share a lot of code between our target platforms, as illustrated in the following diagram. All code that isn't related to the target platform can be shared with other .NET platforms. Code that is typically shared in this way includes business logic, network calls, and data models:
There is also a large community based around the .NET platforms, as well as a wide range of third-party libraries and components that can be downloaded from NuGet (https://nuget.org) and used across the .NET platforms.
Code sharing across platforms leads to shorter development times. It also produces apps of a higher quality because, for example, we only need to write the code for business logic once. There is a lower risk of bugs and are also be able to guarantee that a calculation returns the same result, regardless of what platform our users use.
Using existing knowledge
For .NET developers who want to start building native mobile apps, it is easier to just learn the APIs for the new platforms than it is to learn programming languages and APIs for both old and new platforms.
Similarly, organizations that want to build native mobile apps can use existing developers with their knowledge of .NET to develop apps. Because there are more .NET developers than Objective-C and Swift developers, it's easier to find new developers for mobile app development projects.
The different Xamarin platforms available are Xamarin.iOS, Xamarin.Android, and Xamarin.Mac. In this section, we will take a look at each of them.
Xamarin.iOS is used to build apps for iOS with .NET and contains the bindings to the iOS APIs mentioned previously. Xamarin.iOS uses AOT compiling to compile the C# code into Advanced RISC Machine (ARM) assembly language. The Mono runtime runs alongside the Objective-C runtime. Code that uses .NET namespaces, such as System.Linq or System.Net, are executed by the Mono runtime, while code that uses iOS-specific namespaces are executed by the Objective-C runtime. Both the Mono runtime and the Objective-C runtime run on top of the X is Not Unix (XNU) Unix-like kernel (https://github.com/apple/darwin-xnu), which was developed by Apple. The following diagram shows an overview of the iOS architecture:
Xamarin.Android is used to build apps for Android with .NET and contains bindings to the Android APIs. The Mono runtime and the Android Runtime (ART) run side by side on top of a Linux kernel. Xamarin.Android apps could either be Just-In-Time (JIT)-compiled or AOT-compiled, but to AOT-compile them, we need to use Visual Studio Enterprise.
Communication between the Mono runtime and ART occurs via a Java Native Interface (JNI) bridge. There are two types of JNI bridges—Manage Callable Wrapper (MCW) and Android Callable Wrapper (ACW). An MCW is used when code needs to run in ART and an ACW is used when ART needs to run code in the Mono runtime, as shown:
Xamarin.Mac is used to build apps for macOS with .NET and contains the bindings to the macOS APIs. Xamarin.Mac has the same architecture as Xamarin.iOS—the only difference is that Xamarin.Mac apps are JIT-compiled, unlike Xamarin.iOS apps, which are AOT-compiled. This is shown in the following diagram:
Xamarin.Forms is a UI framework that is built on top of Xamarin (for iOS and Android) and the Universal Windows Platform (UWP). Xamarin.Forms allows developers to create a UI for iOS, Android, and UWP with one shared code base, as illustrated in the following diagram. If we build an app with Xamarin.Forms, we can use XAML, C#, or a combination of both to create the UI:
The architecture of Xamarin.Forms
Xamarin.Forms is more or less just an abstract layer on top of each platform. Xamarin.Forms has a shared layer that is used by all platforms, as well as a platform-specific layer. The platform-specific layer contains renderers. A renderer is a class that maps a Xamarin.Forms control to a platform-specific native control. Each Xamarin.Forms control has a platform-specific renderer.
The following diagram illustrates how entry control in Xamarin.Forms is rendered to a UITextField control from the UIKit namespace when the shared Xamarin.Forms code is used in an iOS app. The same code in Android renders an EditText control from the Android.Widget namespace:
Defining a UI using XAML
The most common way to declare our UI in Xamarin.Forms is by defining it in a XAML document. It is also possible to create the GUI in C#, since XAML is really only a markup language for instantiating objects. We could, in theory, use XAML to create any type of object, as long as it has a parameterless constructor. A XAML document is an Extensible Markup Language (XML) document with a specific schema.
Defining a Label control
As a simple example, let's look at the following snippet of a XAML document:
<Label Text="Hello World!" />
When the XAML parser encounters this snippet, it creates an instance of a Label object and then sets the properties of the object that correspond to the attributes in the XAML. This means that if we set a Text property in XAML, it sets the Text property on the instance of the Label object that is created. The XAML in the preceding example has the same effect as the following:
var obj = new Label()
Text = "Hello World!"
XAML exists to make it easier to view the object hierarchy that we need to create in order to make a GUI. An object model for a GUI is also hierarchical by design, so XAML supports adding child objects. We can simply add them as child nodes, as follows:
<Label Text="Hello World" />
<Entry Text="Ducks are us" />
StackLayout is a container control that organizes the children vertically or horizontally within a container. Vertical organization is the default value and is used unless we specify otherwise. There are also a number of other containers, such as Grid and FlexLayout. These will be used in many of the projects in the following chapters.
Creating a page in XAML
A single control is no use unless it has a container that hosts it. Let's see what an entire page would look like. A fully valid ContentPage object defined in XAML is an XML document. This means that we must start with an XML declaration. After that, we must have one—and only one—root node, as shown:
<?xml version="1.0" encoding="UTF-8"?>
<Label Text="Hello world!" />
In the preceding example, we defined a ContentPage object that translates into a single view on each platform. In order to make it a valid XAML, we need to specify a default namespace (xmlns="http://xamarin.com/schemas/2014/forms") and then add the x namespace (xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml").
The default namespace lets us create objects without prefixing them, such as the StackLayout object. The x namespace lets us access properties such as x:Class, which tells the XAML parser which class to instantiate to control the page when the ContentPage object is created.
A ContentPage object can have only one child. In this case, it's a StackLayout control. Unless we specify otherwise, the default layout orientation is vertical. A StackLayout object can, therefore, have multiple children. Later on, we will touch on more advanced layout controls, such as the Grid and FlexLayout controls.
In this specific example, we will create a Label control as the first child of StackLayout.
Creating a page in C#
For clarity, the following code shows you how the previous example would look in C#:
public class MainPage : ContentPage
page is a class that inherits from Xamarin.Forms.ContentPage. This class is automatically generated for us if we create an XAML page, but if we just use code, we will need to define it ourself.
Let's create the same control hierarchy as the XAML page we defined earlier using the following code:
var page = new MainPage();
var stacklayout = new StackLayout();
Text = "Welcome to Xamarin.Forms"
page.Content = stacklayout;
The first statement creates a page object. We could, in theory, create a new ContentPage page directly, but this would prohibit us from writing any code behind it. For this reason, it's good practice to subclass each page that we plan to create.
The block following this first statement creates the StackLayout control, which contains the Label control that is added to the Children collection.
Finally, we need to assign StackLayout to the Content property of the page.
XAML or C#?
Generally, using XAML provides a much better overview, since the page is a hierarchical structure of objects and XAML is a very nice way of defining that structure. In code, the structure is flipped around as we need to define the innermost object first, making it harder to read the structure of our page. This was demonstrated in the Creating a page in XAML section of this chapter. Having said that, it is generally a matter of preference as to how we decide to define the GUI. This book will use XAML rather than C# in the projects to come.
Xamarin.Forms versus traditional Xamarin
While this book is about Xamarin.Forms, we will also highlight the differences between using traditional Xamarin and Xamarin.Forms. Traditional Xamarin is used when developing apps that use iOS and an Android Software Development Kit (SDK) without any means of abstraction. For example, we can create an iOS app that defines its UI in a storyboard or in the code directly. This code would not be reusable for other platforms, such as Android. Apps built using this approach can still share non-platform-specific code by simply referencing a .NET standard library. This relationship is shown in the following diagram:
Xamarin.Forms, on the other hand, is an abstraction of the GUI, which allows us to define UIs in a platform-agnostic way. It still builds on top of Xamarin.iOS, Xamarin.Android, and all the other supported platforms. The Xamarin.Forms app can be created as a .NET standard library or as a shared code project, where the source files are linked as copies and built within the same project as the platform we are currently building for. This relationship is shown in the following diagram:
Having said that, Xamarin.Forms cannot exist without traditional Xamarin since it's bootstrapped through an app for each platform. This gives us the ability to extend Xamarin.Forms on each platform using custom renderers and platform-specific code that can be exposed to our shared code base through interfaces. We'll look at these concepts in more detail later on in this chapter.
When to use Xamarin.Forms
We can use Xamarin.Forms in most cases and for most types of apps. If we need to use controls that not are available in Xamarin.Forms, we can always use the platform-specific APIs. There are, however, cases where Xamarin.Forms is not useful. The most common situation where we might want to avoid using Xamarin.Forms is if we build an app that should look very different across our different target platforms.
Setting up a development machine
Developing an app for multiple platforms imposes higher demands on our development machine. One reason for this is that we often want to run one or multiple simulators or emulators on our development machine. Different platforms also have different requirements with regard to what is needed to begin development. Regardless of whether we use macOS or Windows, Visual Studio will be our integrated development environment (IDE). There are several versions of Visual Studio, including the free community edition. Go to https://visualstudio.microsoft.com/ to compare the available versions. The following list is a summary of what we need to begin development for each platform:
- iOS: To develop an app for iOS, we need a Macintosh (Mac) device. This could either be the machine that we are developing on or a machine on our network, if we are using one. The reason we need to connect to a Mac is that we need to use Xcode to compile and debug an app. Xcode also provides an iOS simulator. It is possible to do some iOS development on Windows without a connected Mac; you can read more about this in the Xamarin Hot Restart section of this chapter.
- Android: Android apps can be developed on either macOS or Windows. Everything we need, including SDKs and simulators, are installed with Visual Studio.
- UWP: UWP apps can only be developed in Visual Studio on a Windows machine.
Setting up a Mac
There are two main tools that are required to develop apps for iOS and Android with Xamarin on a Mac. These are Visual Studio for Mac (if we are only developing Android apps, this is the only tool we need) and Xcode. In the following sections, we will take a look at how to set up a Mac for app development.
Before we install Visual Studio, we need to download and install Xcode. Xcode is the official development IDE from Apple and contains all the tools available for iOS development, including SDKs for iOS, macOS, tvOS, and watchOS.
We can download Xcode from the Apple developer portal (https://developer.apple.com) or from the Apple App Store. I recommend that you download it from the App Store because this guarantees you have the latest stable version. The only reason to download Xcode from the developer portal is if you want to use a prerelease version of Xcode to develop it for a prerelease of iOS.
After the first installation, and after each update of Xcode, it is important that you open it. Xcode often needs to install additional components after an installation or an update. We also need to open Xcode to accept the license agreement with Apple.
Installing Visual Studio
To install Visual Studio, we first need to download it from https://visualstudio.microsoft.com.
When we start the Visual Studio installer via the file we downloaded, it will start to check what we already have installed on our machine. When the check is finished, we can select which platforms and tools we would like to install.
Once we have selected the platforms that we want to install, Visual Studio downloads and installs everything that we need to get started with app development using Xamarin, as shown:
Configuring the Android emulator
Visual Studio uses the Android emulators provided by Google. If we want our emulator to be fast, then we need to ensure that it is hardware-accelerated. To hardware-accelerate the Android emulator, we need to install the Intel Hardware Accelerated Execution Manager (HAXM), which can be downloaded from https://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager-intel-haxm.
The next step is to create the Android emulator. First, we need to ensure that the Android emulator and the Android OS images are installed. To do this, take the following steps:
- Go to the Tools tab to install the Android emulator:
- We also need to install one or multiple images to use with the emulator. We can install multiple images if, for example, we want to run our app on different versions of Android. We can select emulators with Google Play (as in the following screenshot) so that we can use Google Play services in our app, even when we are running it in an emulator. This is required if, for example, we want to use Google Maps in our app:
- Then, to create and configure an emulator, go to Device Manager in the Android section of the Tools tab in Visual Studio. From Android Device Manager, we can start an emulator if we already have one created; or, we can create new emulators, as shown:
- If we click on the New Device button, we can create a new emulator with the specifications that we need. The easiest way to create a new emulator here is to select a base device that matches our needs. These base devices are preconfigured, which is often enough. However, it is also possible to edit the properties of the device so that we have an emulator that matches our specific needs.
Because we will not run the emulator on a device with an ARM processor, we have to select either an x86 processor or an x64 processor, as in the following screenshot. If we try to use an ARM processor, the emulator will be very slow:
Setting up a Windows machine
We can use either a virtual or physical Windows machine for development with Xamarin. We can, for example, run a virtual Windows machine on our Mac. The only tool we need for app development on our Windows machine is Visual Studio.
Installing Xamarin for Visual Studio
If we already have Visual Studio installed, we first need to open Visual Studio Installer; otherwise, we need to go to https://visualstudio.microsoft.com to download the installation files.
Before the installation starts, we need to select which workloads we want to install.
If we want to develop apps for Windows, we need to select the Universal Windows Platform development workload, as shown:
For Xamarin development, we need to install Mobile development with .NET. If you want to use Hyper-V for hardware acceleration, you can deselect the checkbox for Intel HAXM in the detailed description of the Mobile development with .NET workload on the left-hand side, as in the following screenshot. When you deselect Intel HAXM, the Android emulator is also deselected, but you can reinstall it later:
When we first start Visual Studio, we will be asked whether we want to sign in. It is not necessary for us to sign in unless we want to use Visual Studio Profession or Enterprise, in which case we will need to sign in so that our license can be verified.
Pairing Visual Studio with a Mac
If we want to run, debug, and compile our iOS app, then we need to connect it to a Mac. We can set up our Mac manually, as described earlier in this chapter, or we can use Automatic Mac Provisioning. This installs Mono and Xamarin.iOS on the Mac that we are connecting to. It will not install the Visual Studio IDE, but this isn't necessary if we just want to use it as a build machine. We do, however, need to install Xcode manually.
To be able to connect to a Mac—either manually or using Automatic Mac Provisioning—we need to be able to access the Mac via our network, and we need to enable Remote Login on the Mac. To do this, go to Settings | Sharing and select the checkbox for Remote Login. To the left of the window, we can select which users are allowed to connect with Remote Login, as shown:
To connect to the Mac from Visual Studio, use the Pair to Mac button in the toolbar (as in the following screenshot); or, in the top menu, go to Tools | iOS | Pair to Mac:
A dialog box will appear showing all the Macs that can be found on the network. If your Mac doesn't appear in the list of available Macs, we can use the Add Mac... button at the bottom-left corner of the window to enter an IP address, as shown:
If everything that we need is installed on the Mac, then Visual Studio will connect and we can start building and debugging our iOS app. If Mono is missing on the Mac, a warning will appear. This warning will also give us the option to install it, as shown:
Configuring an Android emulator and hardware acceleration
If we want a fast Android emulator that works smoothly, we need to enable hardware acceleration. This can be done using either Intel HAXM or Hyper-V. The disadvantage of Intel HAXM is that it can't be used on machines with an Advanced Micro Devices (AMD) processor; we have to use a machine with an Intel processor. We can't use Intel HAXM in parallel with Hyper-V.
Because of this, Hyper-V is the preferred way to hardware-accelerate an Android emulator on a Windows machine. To use Hyper-V with our Android emulator, we need to have the April 2018 update (or later) for Windows and Visual Studio version 15.8 (or later) installed. To enable Hyper-V, we need to take the following steps:
- Open the Start menu and type in Turn Windows features on or off. Click the option that appears to open it, as shown:
- To enable Hyper-V, select the Hyper-V checkbox. Also, expand the Hyper-V option and check the Hyper-V Platform checkbox. We also need to select the Windows Hypervisor Platform checkbox, as shown:
- Restart the machine when Windows prompts you to.
Because we didn't install an Android emulator during the installation of Visual Studio, we need to install it now. Go to the Tools menu in Visual Studio, then click on Android and then Android SDK Manager.
Under Tools in Android SDK Manager, we can install the emulator by selecting Android Emulator, as in the following screenshot. Also, we should ensure that the latest version of Android SDK Build Tools is installed:
We also recommend installing the Native Development Kit (NDK). The NDK makes it possible to import libraries that are written in C or C++. An NDK is also required if we want to AOT-compile an app.
The Android SDK allows multiple emulator images to be installed simultaneously. We can install multiple images if, for example, we want to run our app on different versions of Android. Select emulators with Google Play (as in the following screenshot) so that we can use Google Play services in our app, even when we are running it in an emulator.
This is required if, for example, we want to use Google Maps in our app:
The next step is to create a virtual device to use the emulator image. To create and configure an emulator, go to Android Device Manager, which we can open from the Tools tab in Visual Studio. From the device manager, we can either start an emulator—if we already have one created—or we can create new emulators, as shown:
If we click on the New Device button, we can create a new emulator with the specifications that we need. The easiest way to create a new emulator here is to select a base device that matches our needs. These base devices are preconfigured, which is often enough. However, it is possible to edit the properties of the device so that we have an emulator that matches our specific needs.
We have to select either an x86 processor (as in the following screenshot) or an x64 processor since we are not running the emulator on a device with an ARM processor. If we try to use an ARM processor, the emulator will be very slow:
Configuring UWP developer mode
If we want to develop UWP apps, we need to activate developer mode on our development machine. To do this, go to Settings | Update & Security | For developers. Then, click on Developer Mode, as in the following screenshot. This makes it possible for us to sideload and debug apps via Visual Studio:
If we select Sideload apps instead of Developer mode, we will only be able to install apps without going to Microsoft Store. If we have a machine to test, rather than debug our apps on, we can just select Sideload apps.
Xamarin productivity tooling
Xamarin Hot Restart and Xamarin Hot Reload are two tools that increase productivity for Xamarin developers.
Xamarin Hot Restart
Hot Restart is a Visual Studio feature, which is currently in preview, to make developers more productive. It also gives us a way of running and debugging iOS apps on an iPhone without having to use a Mac connected to Visual Studio. Microsoft describes Hot Restart as follows:
Xamarin Hot Restart enables you to quickly test changes to your app during development, including multi-file code edits, resources, and references. It pushes the new changes to the existing app bundle on the debug target which results in a much faster build and deploy cycle."
To use Hot Restart, you need the following:
- Visual Studio 2019 version 16.5 or later
- iTunes (64 bit)
- An Apple Developer account and paid Apple Developer Program (https://developer.apple.com/programs/) enrollment
Hot Restart can currently only be used with Xamarin.Forms apps.
To activate Hot Restart, go to Tools | Options | Environment | Preview Features | Enable Xamarin Hot Restart.
Read more about the current state of Hot Restart at https://docs.microsoft.com/en-us/xamarin/xamarin-forms/deploy-test/hot-restart.
Xamarin XAML Hot Reload
Xamarin XAML Hot Reload allows us to make changes to our XAML without having to redeploy our app. When we have carried out changes to the XAML, we just save the file and it updates the page on the simulator/emulator or on a device. XAML Hot Reload is currently only supported by iOS and Android.
To enable XAML Hot Reload for Visual Studio on Windows, go to Visual Studio | Preferences | Tools for Xamarin | XAML Hot Reload.
To enable XAML Hot Reload for Visual Studio on Mac, go to Tools | Options | Xamarin | Hot Reload.
To use XAML Hot Reload, we have to use Xamarin.Forms 4.1+ with Visual Studio 2019 16.4+ (or Visual Studio for Mac 8.4+).
You should now feel a bit more comfortable about what Xamarin is and how Xamarin.Forms relates to Xamarin itself.
In this chapter, we established a definition of what a native app is and saw how it has a native UI, native performance, and native API access. We talked about how Xamarin is based on Mono, which is an open source implementation of the .NET framework, and discussed how, at its core, Xamarin is a set of bindings to platform-specific APIs. We then looked at how Xamarin.iOS and Xamarin.Android work under the hood.
After that, we began to touch on the core topic of this book, which is Xamarin.Forms. We started off with an overview of how platform-agnostic controls are rendered to platform-specific controls and how to use XAML to define a hierarchy of controls to assemble a page. We then spent some time looking at the difference between a Xamarin.Forms app and a traditional Xamarin app.
A traditional Xamarin app uses platform-specific APIs directly, without any abstraction, other than what .NET adds as a platform. Xamarin.Forms is an API that is built on top of the traditional Xamarin APIs and allows us to define platform-agnostic GUIs in XAML or in code that is rendered to platform-specific controls. There's more to Xamarin.Forms than this, but this is what it does at its core.
In the last part of this chapter, we discussed how to set up a development machine on Windows or macOS.
Now, it's time to put our newly acquired knowledge to use! We will start off by creating a to-do app from the ground up in the next chapter. We will look at concepts such as Model–View–ViewModel (MVVM) for a clean separation between business logic and the UI, and SQLite.NET to persist data to a local database on our device. We will do this for three platforms at the same time—so, read on!