When you first created the Hello solution in Visual Studio, you had a choice of two application tem-plates:
- Blank App (Xamarin.Forms Portable)
- Blank App (Xamarin.Forms Shared)
- Use Portable Class Library
- Use Shared Library
As you’ll see, everything looks pretty much the same, except that the HelloSap project itself con-tains only one item: the App.cs file.
With both the PCL and SAP approaches, code is shared among the five applications, but in decid-edly different ways: With the PCL approach, all the common code is bundled into a dynamic-link li-brary that each application project references and binds to at run time. With the SAP approach, the common code files are effectively included with each of the five application projects at build time. By default, the SAP has only a single file named App.cs, but effectively it’s as if this HelloSap project did not exist and instead there were five different copies of this file in the five application projects.
Some subtle (and not-so-subtle) problems can manifest themselves with the shared library approach:
The iOS and Android projects have access to pretty much the same version of .NET, but it is not the same version of .NET that the Windows projects use. This means that any .NET classes accessed by the shared code might be somewhat different depending on the platform. As you’ll discover later in this book, this is the case for some file I/O classes in the System.IO namespace.
You can compensate for these differences by using C# preprocessor directives, particularly #if and #elif. In the projects generated by the Xamarin.Forms template, the various application projects de-fine symbols that you can use with these directives.
What are these symbols?
In Visual Studio, right-click the project name in the Solution Explorer and select Properties. At the left of the properties screen, select Build, and look for the Conditional compilation symbols field.
In Xamarin Studio, select an application project in the Solution list, invoke the drop-down tools menu, and select Options. In the left of the Project Options dialog, select Build > Compiler, and look for the Define Symbols field.
Here are the symbols that you can use:
- iOS project: You’ll see the symbol __IOS__ (that’s two underscores before and after)
- Android project: You won’t see any symbols defined for indicating the platform, but the identi-fier __ANDROID__ is defined anyway, as well as multiple __ANDROID_nn__ identifiers, where nn is each Android API level supported.
- UWP project: The symbol WINDOWS_UWP
- Windows project: The symbol WINDOWS_APP
- Windows Phone project: The symbol WINDOWS_PHONE_APP
#if __IOS__ // iOS specific code #elif __ANDROID__ // Android specific code #elif WINDOWS_UWP // Universal Windows Platform specific code #elif WINDOWS_APP // Windows 8.1 specific code #elif WINDOWS__PHONE_APP // Windows Phone 8.1 specific code #endif
This allows your shared code files to run platform-specific code or access platform-specific classes, in-cluding classes in the individual platform projects. You can also define your own conditional compila-tion symbols if you’d like.
These preprocessor directives make no sense in a Portable Class Library project. The PCL is entirely independent of the five platforms, and these identifiers in the platform projects are not present when the PCL is compiled.
The concept of the PCL originally arose because every platform that uses .NET actually uses a some-what different subset of .NET. If you want to create a library that can be used among multiple .NET platforms, you need to use only the common parts of those .NET subsets.
The PCL is intended to help by containing code that is usable on multiple (but specific) .NET plat-forms. Consequently, any particular PCL contains some embedded flags that indicate what platforms it supports. A PCL used in a Xamarin.Forms application must support the following platforms:
- .NET Framework 4.5
- Windows 8
- Windows Phone 8.1
- Xamarin.iOS (Classic)
This is known as PCL Profile 111.
If you need platform-specific behavior in the PCL, you can’t use the C# preprocessor directives be-cause those work only at build time. You need something that works at run time, such as the Xamarin-.Forms Device class. You’ll see an example shortly.
The Xamarin.Forms PCL can access other PCLs supporting the same platforms, but it cannot directly access classes defined in the individual application projects. However, if that’s something you need to do—and you’ll see an example in Chapter 9, “Platform-specific API calls”—Xamarin.Forms provides a class named DependencyService that allows you to access platform-specific code from the PCL in a methodical manner.
Most of the programs in this book use the PCL approach. This is the recommended approach for Xamarin.Forms and is preferred by many programmers who have been working with Xamarin.Forms for a while. However, the SAP approach is also supported and definitely has its advocates as well. Pro-grams within these pages that demonstrate the SAP approach always contain the letters Sap at the end of their names, such as the HelloSap program.
But why choose? You can have both in the same solution. If you’ve created a Xamarin.Forms solu-tion with a Shared Asset Project, you can add a new PCL project to the solution by selecting the Class Library (Xamarin.Forms Portable) template. The application projects can access both the SAP and PCL, and the SAP can access the PCL as well.
I hope I have helped in something. Until the next opportunity!