If you’re building a new smartphone or tablet app, the question you’ve likely pondered upon was which platforms (and form factors) are you going to support.
Whether you are building one platform for both phone and tablet, or two platforms just for phone, or even whether the phone and tablet versions should be different, this choice should be made carefully in case your mind changes later. According to YAGNI, you don’t want to over-engineer, but in choosing a development stack you also don’t want to settle on a path that will prevent you from being able to share code in future work.
After you conclude on this, the next is to decide on which stack you’re going to be developing it under. This choice can lock you into commitments you may not have even thought of yet, so choose with forethought. There isn’t a universally wrong answer, but each has its tradeoffs that you have to be okay with.
The Purely Native Stack
This is the happy path for each platform, so things should just work. You will have the most support here, and any question you can think of has already been answered. You can take full advantage of the platforms’ features and have confidence that your toolkit is as the OS developers intended.
However, you don’t get to share any code. Not unless most of your functionality uses WebServices, or if your shared business logic is written in C or C++. If you are using C/C++ code, the native development stacks have full support for it.
Interfacing with C/C++
For iOS, you can use Objective-C++ which is a superset of Objective-C that allows you to write C++ directly inside Objective-C-like code. If you’re coding your app in Swift, you can setup Swift to Objective-C interfaces, which is compatible with Objective-C++.
On Android, you need the NDK to compile C++ and you will also need to write JNI (Java Native Interface) bindings to call into the native code and marshal values between the two languages. A tool called SWIG can help with generating these.
On Windows UWP, you can still use C# to P/Invoke to C/C++ code, however there may be some restrictions to using native Win32 code, but there are ways to get around it. Also, if you have C++ source, you can manage to get it to compile into a compatible native binary.
For the UI/UX side of things, the native development stack will be the easiest to customize, and will also have more established third-party UI libraries you can use when the default widgets aren’t providing the User Experience that is trending at the time.
Cross Platform with C#
Close to two decades ago, I recall that a certain megalith’s selling point of .Net being cross-platform was being able to run on all versions of Windows (98/ME and 2000/XP), on x86 or ia64 chips. Hardly groundbreaking I thought, as C# came after Java, which was already running on Windows, Mac, Linux and all the other Unices and processor architectures at the time.
Some short years after the .Net announcement, the Mono project had released an Open Source C# compiler and runtime. Given the rumours of anti-Linux sentiments from earlier said megalith at the time, it would take an open mind or a visionary to really see the purpose of this effort. Miguel de Icaza and his team did not fail to see the possibilities of an Open Source .Net implementation.
This was the beginning of a C# platform beyond Windows, beyond desktop computers, that would eventually come full circle back to said megalith. Acquiring Xamarin could easily have been Microsoft’s best move in staying relevant in the mobile software space. Oh, how the times have changed.
If you are targeting both Android and iOS, there are different ways you can use Xamarin, and there is generally not a “wrong” approach from the following, but rather better ways depending on your product and the circumstances. How much code you want to share, if any is also a deciding factor.
Xamarin Native Stack
At the API level, Xamarin.iOS and Xamarin.Android can be looked at as a C# wrapper to the iOS and Android native stacks, respectively. This wrapper is so thin that calling it an abstraction would be wildly and completely inaccurate. All of the native API calls exist, just in different syntax. And some of C#’s syntactic sugar does make things smoother and cleaner (such as .Net events as opposed to the delegate patterns used in Objective-C and Java). The performance difference with this additional layer is negligible for the most part, but there might be some exceptions.
Using this stack, you can share most of your business/domain logic, but there are platform-specific ways to access hardware and OS features; you will have to be smart at abstracting the platform-specific code from the platform-agnostic code in a way that is maintainable. If you can follow SOLID design principles, support some rendition of MVC, and properly organize your Visual Studio build targets, then coming up with a reusable pattern shouldn’t be much of a problem.
The User Interface is another area that will have to be implemented separately between platforms, but you can share the code that talks to the UI. Ensuring your concrete Views implement a common “ISomethingView” interface that your MVC Controller speaks with can help code reuse. Your View interfaces should have a definition of commands and events which are communicated in meaningful, yet platform-agnostic terms.
One challenge would be sharing code for things which are conceptually different between the Mobile platforms. If one platform doesn’t have an equivalent, or is solving a problem in a completely different manner, then it may not be a simple 1:1 Liskov substitution.
If you are using third-party libraries, Xamarin has mechanisms to use both native Android libraries or native iOS libraries. If you have some code in C++, you may also use P/Invoke (presumably generated by SWIG) to wrap it in C# for Xamarin consumption; the Xamarin.iOS and Xamarin.Android linkers will allow you to hook them into the final native binary.
Xamarin Forms Stack
Xamarin Forms takes the Xamarin stack further and allows you to share your UI code between Android, iOS and Windows UWP apps through a high level of abstraction. The caveat to this, is that only UI components which are common between all 3 platforms are going to be abstracted — anything unique will have to be customized. It is because of this that you might find the out-of-the-box UI widget set to be lacking certain functionality available in their native counterpart. This is remedied by the following concepts…
Xamarin Forms has built-in support for you to define your own cross-platform controls, layouts and templated view components. Or to drop down even lower you can access the Xamarin native APIs for the platform-specific bits via “Custom Renderers”. This means that any User Interface APIs which are available from a native development stack is also available, in C# form. In the spirit of sharable code I believe this can be done sparingly, when possible, as there are other techniques to use (such as Effects) to avoid having to resort to this. Custom Renderers are not completely avoidable, but there comes a point if you are finding yourself writing more renderers than shared UI code, then maybe native Xamarin is a better choice, but also likely you need to re-visit how you’re approaching your User Interface design.
Xamarin Forms controls can also be inserted into Xamarin native projects to some extent and vice-versa. This allows some flexibility if you need to Frankencode up a solution.
Xamarin Forms UI is normally defined in XAML with C# code-behinds and uses the MVVM paradigm, which is very similar to WPF or the Windows Metro/Modern UI. If you don’t want to take advantage of the prescribed framework and patterns, there’s nothing stopping you from writing all of your UI in C# and using MVC or a pattern of your choice, but XAML makes the view hierarchy much easier to read.
In addition to UI code, Xamarin Forms also allows you to create a more platform-agnostic application shell for your Visual Studio solution, with the abstraction of hooks of the mobile application lifecycle. This also includes APIs for running background tasks and executing blocks back on the UI thread, so you can do some cleaner looking async work without the worry of how the OS needs to deal with it.
UI Frameworks on Top of Xamarin
There is nothing stopping you from building your own UI framework on top of Xamarin or even on top of the foundation for Xamarin Forms, if Xamarin Forms doesn’t suit your fancy for UI code re-use.
If you choose to go this way, you will be very far off the happy path, and I wouldn’t recommend it if UI frameworks isn’t your core competency or if you’re not also an expert in the native mobile UI concepts. The initial work is a full time job, and the maintenance will be ongoing indefinitely, so if you have other business problems to solve then taking this on can be a slippery slope.
Code sharing between Android and iOS, and even UWP, is easily within reach when using Xamarin. The C# language is modern and has advanced gracefully over the years, is fun to play with, and is still very easy to pickup.
Using the Xamarin stack alone will open up code reuse but in order to maximize reuse, you must use good judgment in both code architecture and in your overall solution structure. These concepts don’t come naturally by throwing code together, but come with experience and planning.
A software development shop with mostly C# experience might be keen to choose Xamarin to share code with their legacy applications. Use this choice with caution however, as I’ve outlined in my other article that sharing desktop code has its caveats.