A typical Xamarin solution structure
A Xamarin solution can be composed of different types of projects. Some of these projects are platform-specific projects and the others are shared project types or modules that make it possible to reuse code across platforms.
Figure 11: Xamarin project solution structure on Visual Studio and Xamarin Studio
Portable class libraries
Portable class libraries are the most common way of sharing code between cross-platform projects. PCLs provide a set of common reference assemblies that enable .NET libraries and binaries to be used on any .NET-based runtime or with Xamarin compilers—from phones to clients, to servers and clouds. PCL modules are designed to use only a specific subset of the .NET framework and can be set to target different platforms.
Figure 12: Portable Class Library Targets
Microsoft has a designation for each target combination and each profile also gets a NuGet target. A subset of .NET libraries for portable class libraries were released through NuGet with the release of Visual Studio 2013. This makes it possible for developers to release their work through NuGet packages, targeting a wide range of mobile platforms (see the NuGet packages section for more information).
Note
The currently preferred profile and the greatest common subset for Xamarin projects is the so-called Profile 259. The Microsoft support designation for this profile is the .NET Portable Subset (.NET Framework 4.5, Windows 8, Windows Phone 8.1, Windows Phone Silverlight 8) and the NuGet target framework profile is portable-net45+netcore45+wpa81+wp8
.
While creating a PCL, the biggest drawback is the fact that no platform-specific code can be included in or referenced by the project. This caveat is generally addressed by the abstraction of platform-specific requirements or by using dependency injection or similar methods to introduce the implementation in platform-specific projects.
For instance, in the device-specific peripheral example below, the common portable class library has a constructor that accepts two separate interfaces which can be injected with a dependency injection container or can be initialized with a device-specific implementation. The common library, in return, creates a business logic implementation, as shown:
namespace Master.Xamarin.Portable { public class MyPhotoViewer { private readonly IStorageManager m_StorageManager; private readonly ICameraManager m_CameraManager; public MyPhotoViewer(IStorageManager storageManager, ICameraManager cameraManager) { m_StorageManager = storageManager; m_CameraManager = cameraManager; } public async Task TakePhotoAsync() { var photoFileIdentifier = await m_CameraManager.TakePhotoAndStoreAsync(); var photoData = await m_StorageManager.RetrieveFileAsync(photoFileIdentifier); // TODO: Do something with the photo buffer } } /// <summary> /// Should be implemented in Platform Specific Library /// </summary> public interface IStorageManager { Task<string> StoreFileAsync(byte[] buffer); Task<byte[]> RetrieveFileAsync(string fileIdentifier); } /// <summary> /// Should be implemented in Platform Specific Library /// </summary> public interface ICameraManager { Task<string> TakePhotoAndStoreAsync(); } }
Shared projects
The term, shared project, was initially coined by the Microsoft team with the release of Universal Apps for Windows Phone and Windows Runtime (that is, Visual Studio 2013). With the arrival of Xamarin, shared projects can also be referenced by Android and iOS projects. These types of projects are essentially wrappers or containers for shared code and resource files that are linked to multiple projects and platforms. Shared file assets are included in the referencing projects later and compiled as part of these modules.
Figure 13: Shared Projects
While using shared projects, developers should be careful when including platform-specific code since the shared elements will be included in all the referencing projects and compiled. Compiler directives (for example, #if __ANDROID__
) can be introduced in shared projects to denote that certain parts of the code are only for a specific platform.
Tip
Visualizing platform-specific code in shared projects
With Visual Studio (2013 or higher), it is possible to visualize different execution paths according to the combinations of conditional compilation constants.
Figure 14: Visual Studio shared project editor
Visual Studio provides a dropdown in the top corner of the editor window which determines the platform-specific projects that are referencing the shared project. By selecting the project, you can see the disabled sections of the code, according the target platform.
If we used the same example to take a photo, we would need to create two completely different implementations for the same action, as shown here:
private async Task<string> TakePhotoAsync() { string resultingFilePath = ""; var fileName = String.Format("testPhoto_{0}.jpg", Guid.NewGuid()); #if __ANDROID__ Intent intent = new Intent(MediaStore.ActionImageCapture); var file = new File(m_Directory, fileName); intent.PutExtra(MediaStore.ExtraOutput, Net.Uri.FromFile(_file)); // TODO: Need an event handler with TaskCompletionSource for // Intent's result m_CurrentActivity.StartActivityForResult(intent, 0); resultingFile = file.AbsolutePath; #elif WINDOWS_PHONE_APP ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg(); // create storage file in local app storage var file = await LocalStore.CreateFileAsync(fileName); resultingFilePath = file.Path; // take photo await capture.CapturePhotoToStorageFileAsync(imgFormat, file); #endif return resultingFile; }
Xamarin.Forms
Xamarin.Forms is the unified library for creating UI implementations for target platforms to be rendered with native controls. Xamarin.Forms projects are generally created as PCL projects and can be referenced by Xamarin.iOS, Xamarin.Android, and Windows Phone development projects. Xamarin.Forms components can also be included in shared projects and can utilize platform-specific features.
Developers can effectively create common UI implementations with these forms, either declaratively (with XAML), or by using the API provided. These views, which are constructed with Xamarin.Forms components, are then rendered at runtime with platform-specific controls.
Development projects can be realized with Xamarin.Forms by creating the data access model up until the UI components with a shared implementation, thus raising the amount of shared code between the platforms to as much as, or at times more than, 90%.
NuGet packages
NuGet, which was initially an open source Microsoft initiative to share code among developers, has now become a much larger ecosystem. While NuGet servers can be used as an open source library-sharing platform, many development teams use NuGet as a private company repository for compiled libraries.
NuGet packaging is a viable code-sharing and reuse strategy for Xamarin projects since it is supported by both Xamarin Studio and Visual Studio (with no further installation following Visual Studio 2012).
The NuGet target framework moniker for Xamarin projects is mono and there are further groupings such as MonoAndroid10, which refers to projects with a target framework of MonoAndroid version 1.0 or higher. Other platform targets are:
- MonoAndroid: Xamarin.Android
- Xamarin.iOS: Xamarin.iOS Unified API (supports 64-bit)
- Xamarin.Mac: Xamarin.Mac's mobile profile
- MonoTouch: iOS Classic API
Developers are free to either re-use publicly available NuGet packages or create their own repository to store compiled packages to include in Xamarin projects.
Tip
Creating NuGet packages in Visual Studio 2015
With the release of Visual Studio 2015, there is a new project template that should help developers to create and reuse NuGet packages.
Figure 15: The Visual Studio NuGet package project template
More information on creating NuGet packages and publishing them can be found on the NuGet documentation hub: (http://docs.nuget.org/create/creating-and-publishing-a-package)
Components
Components are another approach to re-using compiled libraries and modules in Xamarin projects. The Component Store is built into both Xamarin Studio and Visual Studio and it has gathered a number of re-usable submissions from developers since its release in 2013. Components can be downloaded and installed into projects in the same way as for NuGet packages by using the Xamarin Component Store. The Xamarin Component Store can be found at https://components.xamarin.com.