Xamarin Tips and Tricks #2 – Beware of Linking and Reflection

Recently I ran into an issue where code worked perfectly fine in Debug mode, but not in Release mode. It was on a Xamarin.Android project using MvvmCross and certain bindings did not work as expected in Release mode. Bonus points if you already know what the issue is :). For those of you who don’t, stay with me.

So, first thing you do is check out the Android Build options for the Debug and Release configurations and see what’s different between the two.



The first difference is the Use shared Mono run-time option which is only enabled for Debug builds, and SHOULD only be enabled for Debug builds, you cannot use this in production! As the description says, it speeds up deploying your app during development by only deploying the shared run-time code once. More information about this can be found in the Advanced Topics on the Xamarin developer website.

The other difference is Enable developer instrumentation, which is necessary for e.g. setting break points during debugging.

Both options don’t seem likely candidates to me for causing the issues I’m seeing. Let’s have a look at the Linker tab.



The Linker behavior is different. So, what does the Linker do? From the Xamarin docs on Linking:

Xamarin.Android applications use a linker in order to reduce the size of the application. The linker employs static analysis of your application to determine which assemblies are actually used, which types are actually used, and which members are actually used.

The key here is Static Analysis! Anything that is determined during run time cannot be caught by the linker, e.g. code using Serialization or Reflection. And this is exactly what MvvmCross does, using Reflection to bind to Commands and Properties.

Xamarin provides a few options to explicitly preserve members by the linker. One of them is to use the Android.Runtime.PreserveAttribute, but you can only use that if you control the code. The other option is to make the linker think that a certain type is being used. Luckily, the maker of MvvmCross already thought about this and included a default LinkerPleaseInclude.cs file in the MvvmCross nuget package. However, this is just a default (minimum) implementation and you might need to add your own code in here to preserve types that you are using.

In my case I had to add the following code snippets for preserving the Enabled property of the ImageButton and EditText and the Visibility property of the TextView.

public void Include(ImageButton button)
    button.Click += (s,e) => button.Enabled = !button.Enabled;

public void Include(TextView text)
    text.TextChanged += (sender, args) => text.Text = "" + text.Text;
    text.Hint = "" + text.Hint;

    text.Click += (s, e) => text.Visibility = text.Visibility - 1;

public void Include(EditText text)
    text.Click += (s, e) => text.Enabled = !text.Enabled;

So, hopefully this saves you some time when troubleshooting Xamarin.Android Linker problems.

Some resources that helped me:

Happy coding!