Everything that is wrong with Xamarin and why it is bad for you

Jan Rabe
5 min readOct 16, 2018

--

Here is what I’ve found out working with Xamarin past 7 months.

TL;DR

You need 3 open IDEs to work efficiently. Visual studio mac is the worst! Debugging sucks. Logging sucks. Compile time is inherently longer. App-Size scales terrible. Horrible design decision to force the app-developer to maintain the solution file. The Xamarin community leaves to be desired. Outdated dependencies, in general the dependency management is unreliable and crap. Lots of unnecessary code just to access android sdk / dependency features.

Debugging

  • doesn’t show correct StackTraces, particularly no external java dependencies
  • has trouble debugging threads
  • detaches almost always debugger after jumping into function
  • many steps in order to get to actual variable values of a break point
  • re-arranges windows during debugging and there is no apparent way to save window positioning
  • disassembling: you don’t jump to a particular implementation instead it scrolls to the main assembly and shows the jni bindings for it, which essentially is not what you’re interested in

Logging

In Xamarin you have a Device Log and an Application Output.

  • Device Log is practically unusable due no filtering and way too much noise
  • Application Output lots of noise too, no filtering, no search

App-Size

  • it has to compile jni bindings for every cpu architecture, which means it adds the un-proguarded jar/aar dependencies in your app as well as every jni binding 5times for armeabi, armeabi-v7a, arm64-v8a, x86, x86_64
  • nuget dependencies include more than you usually need for compatibility sake (e.g. for adding recyclerview support lib, you need to add the entire arch/support dependencies which >160k methods/static vars

Xamarin Android

  • AndroidManifest configuration is split all over in the project using annotations, which seems nice at first but makes it actually quite hard to maintain
  • interacting with Android SDK classes within C# forces you to write java.lang.Object wrappers for every listener instead of having a simple function call

Tooling Stack

  • for compiling and application output Visual Studio Mac
  • for writing code I’d recommend using Rider so you don’t turn insane from the horrendous abomination of a text-editor called Visual Studio Mac
  • for layouts I’d recommend using a separate Android Studio project and reference the resource folder
sourceSets {
main {
res.srcDirs = ['../../Droid/Resources']
res.exclude { '../../Droid/Resources/values/colors.Designer.cs' }
}
}

Pricing

Visual Studio Mac

  • MonoDevelop fork with basically no reasonable code formatting and still having the same formatting issues since 2013

Indentation became a big problem for me. When a just press ENTER and move to the new line MD adds one more tab to the beginning of the line. So after every ENTER pressing I need to press BACKSPACE.
- Andrey-Postelzhuk, Nov 26, 2013

  • auto imports are slow (you have to wait, and often press alt+enter few times before the correct import context menu pops up)
  • don’t work for static imports, e.g. extension methods
  • Agonising auto-complete and search, where it shows search results in an undesired sort order
  • Android Layout editor is not able to correctly render or format android xml layouts
  • You need a clean script, since the Build/Clean is not removing obj folders or invalidating caches correctly which leads to more frequent full builds

Here the clean script we need to run approximately after every 5th build.

Compiling

  • horrendous compile times, no way of fixing it
  • compile time hang ups which lead to full re-builds or even ide restarts

C# Solution file

The solution file references files instead of reflecting the project file structure. Therefore as an app-developer you need to manage all code-/resource- and asset files, as well as all dependencies, references and build types yourself.

Which is bad because it contradicts convention over configuration. There are already conventions where file for resources, assets, code, etc. should be located in.

It adds unnecessary complexity and a lot of your daily development in a week gets wasted while merging solution files and fixing broken references when adding nugets, even though these kind of problems shouldn’t be a problem in the first place.

Community

  • default solution to literally every question is please delete obj/bin-folders, which fixes only symptoms instead of causes, which leads to repeating tasks, long rebuilds and scales extremely poorlyCompared to native, very few packages available and the ones that exist are out-dated at least 3–6 months on average
  • official Xamarin Github repositories, e.g. GooglePlayServicesComponents and AndroidSupportComponents have extremely slow (≥ 3–6 months) response times to issues and pull-requests
  • Missing new goodies
  • no jetpack
  • arch navigation simply doesn’t work because Xamarin doesn’t support resource/navigation folder even if you bind the navigation library
  • no d8/r8
  • outdated support libraries, have fun adding workarounds to recyclerView bugs that were fixed over a year ago
  • no synthetic android imports, which means you’re stuck with the infamous findById or it’s slightly less painful butterknife version aka cheeseknife version

Dependencies

Binding jars/aars

  • automatic bindings work unless you have dependencies, then you need to create a binding project for each and every one dependency
  • it also almost always fails when generics are involved due to differences between generic type system in c#/java, then you have to write your own meta definition files
  • overcomplicated
  • large overhead
  • unreasonable increase of file size per jar/aar-ratio

Extending / updating dependencies

TL;DR too much overhead and way too many steps

Necessary Steps:

  1. fork github project
  2. extend/fix github project
  3. get all dependencies of that github project
  4. create new Xamarin binding for every dependency and sub-dependency, etc. with possibly huge amounts of meta transforms
  5. upload binding to nuget or move to local nuget repository and then finally add to your project

Example:

Native Android: https://github.com/payworks/mpos-ui.android.paybutton -> plug & play

Xamarin way: 3 days of work to bind as library: https://github.com/kibotu/Xamarin.Android.Io.Payworks.Mpos

including bindings for

  • Bolts.Android
  • Couchbase.Lite.Android
  • Couchbase.Lite.Android.Custom
  • Couchbase.Lite.Android.ForestDB
  • Couchbase.Lite.Java.Core
  • Jackson.Annotations
  • Jackson.Core
  • Jackson.Databinding
  • Mpos.Android.Core
  • Mpos.Android.Ui (the one we need)
  • Mpos.Core
  • Otto
  • StateLess4j

Emulator

  • it often doesn’t work to run builds using Visual Studio Mac
  • quite annoying: it auto-selects the emulator over the selected usb device after every 2nd/3rd build for no apparent reason; my best guess is that there is an adb timeout and it just deploys to the next best device instead of canceling the build task

Workaround: uninstall every emulator.

--

--

Jan Rabe

Technical Team Lead Native Apps at CHECK24 Profis. Native Android & Unity3D VR/AR Developer and Technocrat. https://kibotu.net