When using shared projects, file linking, or cloned project files, one of your most powerful tools is the use of preprocessor statements. If you are unfamiliar with them, C# has the ability to define preprocessor variables such as #define IPHONE
, allowing you to use #if IPHONE
or #if !IPHONE
.
The following is a simple example of using this technique:
#if IPHONE Console.WriteLine("I am running on iOS"); #elif ANDROID Console.WriteLine("I am running on Android"); #else Console.WriteLine("I am running on ???"); #endif
In Xamarin Studio, you can define preprocessor variables in your project's options by navigating to Build | Compiler | Define Symbols, delimited with semicolons. These will be applied to the entire project. Be warned that you must set up these variables for each configuration setting in your solution (Debug and Release); this can be an easy step to miss. You can also define these variables at the top of any C# file by declaring #define IPHONE
, but they will only be applied within the C# file.
Let's go over another example, assuming that we want to implement a class to open URLs on each platform:
public static class Utility { public static void OpenUrl(string url) { //Open the url in the native browser } }
The preceding example is a perfect candidate for using preprocessor statements, since it is very specific to each platform and is a fairly simple function. To implement the method on iOS and Android, we will need to take advantage of some native APIs. Refactor the class to look as follows:
#if IPHONE //iOS using statements using MonoTouch.Foundation; using MonoTouch.UIKit; #elif ANDROID //Android using statements using Android.App; using Android.Content; using Android.Net; #else //Standard .Net using statement using System.Diagnostics; #endif public static class Utility { #if ANDROID public static void OpenUrl(Activity activity, string url) #else public static void OpenUrl(string url) #endif { //Open the url in the native browser #if IPHONE UIApplication.SharedApplication.OpenUrl(NSUrl.FromString(url)); #elif ANDROID var intent = new Intent(Intent.ActionView,Uri.Parse(url)); activity.StartActivity(intent); #else Process.Start(url); #endif } }
The preceding class supports three different types of projects: Android, iOS, and a standard Mono or .NET framework class library. In the case of iOS, we can perform the functionality with static classes available in Apple's APIs. Android is a little more problematic and requires an Activity
object to launch a browser natively. We get around this by modifying the input parameters on Android. Lastly, we have a plain .NET version that uses Process.Start()
to launch a URL. It is important to note that using the third option would not work on iOS or Android natively, which necessitates our use of preprocessor statements.
Using preprocessor statements is not normally the cleanest or the best solution for cross-platform development. They are generally best used in a tight spot or for very simple functions. Code can easily get out of hand and can become very difficult to read with many #if
statements, so it is always better to use it in moderation. Using inheritance or interfaces is generally a better solution when a class is mostly platform specific.
18.225.255.187