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.

options-debug-general

options-release-general

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.

options-debug-linker

options-release-linker

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!

  • Adrien Padol

    Have you tried setting the Linker Behavior to “Link SDK Assemblies only” before doing any include ? It’s supposed to be less “aggressive” than “Link All Assemblies” ?

    • Hi Adrien, good suggestion. Indeed that’s less aggressive and I tried it, but it still didn’t work for me.

  • jmix90

    Thank you for sharing, you saved my day 🙂

  • N Baua

    Hi,
    I wanted to include every plug-in I used for the project (the imagecirecle, settings and media plug-in), so I read somewhere in XF forums to create a mock class and make instances of your plug-ins or 3rd party assemblies and set the PreserveAttribute on that mock class, not sure if this is going to work, I am planning to test it that way when I am done with my App.