I've been in charge of the mobile development at my office for the last 3 years; in fact, the reason I was first hired was because they wanted to expand into Android, and decided to hire a separate developer for the job. We started off with a single app on a single platform, but it eventually ballooned into six apps across two (Android and iOS). Part of this was probably not the best choice in hindsight. The original plan was to try to license each app separately to our clients, but that didn't really make a lot of sense and was scrapped pretty early on.
Regardless, maintaining six apps quickly turned into a bit of a chore. Some of the code was centralized, but because of the timing, the Android codebase ended up a little bit messier than the iOS ones. We also never had enough time to go back and refactor things to get them into better shape, so the mediocre architecture got dragged through a couple of releases.
This release I was finally able to get the green light for some much needed UI updates, so I decided to pitch the project with two added goals:
- Refactoring the codebase into two apps, one for each platform. This was a big win in everyone's opinion, since it made the apps easier to understand and made my workload much lighter.
- Rewriting the apps in a cross-platform framework. Again, the idea here was to save time in the long run. It was, in my opinion, an issue of opportunity cost.
.NET for the mobile world
As a third option, I decided to do some research on Xamarin. It seemed like an interesting prospect, and I had actually looked at the project way back when it first launched.
Xamarin has a bit of a convoluted history, but the gist of it is that it ultimately came about after Novell decided to ax the Mono team. In a sense, it was probably a good decision for Novell. Mono never really came to the scene on Linux the way they expected it to, and Moonlight - their open source implementation of Silverlight - had trouble getting off the ground because it was encumbered by DRM difficulties when dealing with streaming video.
So Novell cut Mono loose and it spawned Xamarin, a new company that took over the reins of the Mono Project. They later released the eponymous Xamarin framework with the goal of bringing .NET to mobile devices by essentially porting Mono to ARM.
The end result is pretty impressive, really. You get the flexibility and power of C#, including all the great language features that you can use in desktop and web settings (like LINQ and async/await programming) combined with access to the native SDKs for the platforms you're working with. Since they wrap the native SDK libraries, hardware features are generally supported within a few weeks of their addition to the upstream projects. They had an iOS 7 compatible SDK out the door the same day.
Plus, the ability to use the same language on both Android and iOS meant I could finally share code between platforms. That was huge, and the prospect of being able to write a "logic" layer that was used on both apps was incredibly attractive. Now, after 3 months (one release cycle) with Xamarin, I feel like I'm at a point where I can jot down my impressions of the project.
What it does well
For a comparatively young project, Xamarin is really quite polished. I use Visual Studio 2012 on my Windows machine, with the relevant Xamarin add-ons installed, and Xamarin Studio (their own IDE) on my Mac Mini. Both work quite well, and I'm particularly impressed with how fully featured Xamarin Studio is when compared to other IDEs. There are file templates for various types of views and view controllers (depending on the platform), as well as a project template specifically for creating C# bindings for native libraries. This is a huge plus, since it means you can leverage the extensive collection of third-party libraries that are out there for Android and iOS without a whole lot of fuss (or porting tons of code).
Code sharing is incredibly convenient, although it can be a little tricky to get set up at the start. Support for Portable Class Libraries exists, but it's very much in its infancy at this point, and I had difficulty getting it to work well. The other problem with PCLs is that you only have access to classes which have been implemented on all supported platforms, and not all pieces of the .NET framework have been ported. If you need to use something that's not available to one of the PCL target platforms, you can't use a PCL.
Instead, I found the easiest thing to do is to set up a project for the "core" code, then one project each for Android and iOS that contained the UI and platform-specific code. Then, instead of building the core as a library, I simply linked the files into the other projects. This required some preprocessor directives in a few places where I needed different implementations between the two, but luckily, you get some constants for this;
#if __ANDROID__ and
#if __IOS__ will allow you to conditionally compile specific segments of code. The payout, though, is that you get all the great C# language features like LINQ and async programming, which are simply fantastic.
Debugging is mostly pleasant, inasmuch as debugging can be considered pleasant, anyway. You can set breakpoints and inspect variables just like with ordinary .NET code running in Visual Studio, and all the typical exception handling tools are available (break on all, and such). You also get the standard code navigation tools, so you can jump to a method definition or find all references to a class easily. On the whole, it feels just like any other C# app, and you forget you're actually writing for mobile when you're deep into the logic layers of your code.
Support for each platform is great in pretty much every aspect. Hardware support is excellent, exposing all of the native APIs that would normally be available for each platform. You get native UI widgets and classes, so your interfaces are native, rather than being HTML that's simply styled to look native. Since it's compiling down to a native app, the end-user really has no indication that you're using a third-party framework.
Another cool feature is the ability to write and deploy iOS apps from Visual Studio, rather than having to use Xamarin Studio. The downside is that you can't edit certain files (storyboards, notably) without Xamarin Studio, but if you need to make a quick change to some logic you can do it all without ever leaving your Windows machine. There is a catch, however, which is that you still need a Mac to act as a build server. This means you need to have the Mac on the same network as the Windows machine (it will use Bonjour to find it) and the Mac must have the Xamarin.iOS SDK installed.
Where it's a little complicated
Although Xamarin does a lot of things well, it does have a few problematic areas. One is that the Visual Studio add-on is weirdly picky about which variables it will let you inspect. I found myself trying to look at static properties on occasion, only to be greeted with a tooltip that read "Unknown Identifier". This made debugging a bit awkward in some circumstances, but it is certainly something you can work around.
I've also found that Xamarin's iOS workflow leaves something to be desired, particularly if you want to use storyboards. Unfortunately, Xamarin doesn't have any kind of editor for storyboard files, so when you open one it simply launches XCode and opens that. A side effect of this is that you end up with a sort of "shadow" XCode project for your Xamarin project, which is a little weird.
I also found that Xamarin Studio was a bit prone to odd errors for no particular reason. This seemed to be exacerbated by using XCode, occasionally causing Xamarin Studio to simply crash when trying to regenerate the C# files for my view controllers. At other times, the auto-complete system would seemingly die, prompting me to send an error report before restarting itself a moment later. Not deal breakers, by far, but I definitely found myself working slower on iOS than on Android.
Lastly, I ran into some instances where deploys didn't quite go as they should. Usually the app would install, but then freeze when trying to load, and the debugger would disconnect itself. In these cases, redeploying was enough to kick everything into gear properly. Other times, deploys would fail to install pieces of the Mono runtime on the device, and the only solution I found was to completely uninstall everything (Mono and the app) and redeploy it all. This was a bit time consuming, taking a few minutes to install the Mono runtime on the device, but otherwise not a huge deal.
It is worth it?
There is one other thing that sets Xamarin apart from some of its contemporaries, and that's the licensing cost. For small companies (like mine), it costs $999 per platform for one year, meaning our total cost was about $2000. This gets you a license for one developer across 3 machines, which is not bad, but can get tight if you plan to work from home and the office. I wouldn't have enough licenses to run two Windows machines and two Macs as build machines, for example (I don't anyway since I don't own a Mac).
Despite the initial cost, though, I think Xamarin is definitely worth the investment if you're looking to support multiple platforms. The sheer amount of time I can save is going to make up for the money spent, and I feel like the debugging I did this release was actually faster than the debugging I did using the native IDEs. Part of this, surely, is that Visual Studio has become quite a mature project, so leveraging that is hugely beneficial. However, Xamarin Studio is really quite capable on its own as well.
Ultimately, I'm very pleased with Xamarin, and I think it was the right decision for our company. Moving forward, I'll be able to maintain my codebase much more easily, and with a much cleaner architecture than if I was using another cross-platform framework.