Xamarin.Android Publishing your Xamarin.Android APK Enabling MultiDex in your Xamarin.Android APK


Example

MultiDex is a library in the Android APK that allows the app to have more than 65,536 methods.

The Android APKs have Dalvik Executable files (.dex) that contain the generated bytecodes compiled from your Java code. Each .dex file can contain up to 65,536 methods (2^16).

Android OS versions before Android 5.0 Lollipop (API 21) use the Dalvik runtime, which only supports one .dex file per APK, limiting to 65,536 methods per APK. Starting from Android 5.0, the Android OS use ART runtime, which can support more than one .dex file per APK, avoiding the limit.

To surpass the 65k methods limit in Android versions below API 21, the developers must use the MultiDex support library. The MultiDex creates extra classes.dex files (classes2.dex, classes3.dex, ...) referencing them in the classes.dex file. When the app starts loading, it uses an MultiDexApplication class to load the extra .dex files.

If your Android app aims for a minimum SDK version above or equal to API 21 (Android 5.0 Lollipop) it is not necessary to use the MultiDex library, because the OS handles natively the extra .dex files. However, if for compatibility reasons the developer wants to support older Android OS, then he/she should use the MultiDex library.


How to use MultiDex in your Xamarin.Android app

First, to enable MultiDex in your Xamarin.Android app, go to your project Properties -> Android Options -> Packaging -> Enable Multi-Dex, as in the print screen below:

Enable MultiDex option

Then, you must create a MultiDexApplication class in your app. In the project's root, create a new class (in the Solution Explorer, right-click in the project, Add.. -> Class, or Shift+Alt+C). In the new class file, copy the following code, replacing the namespace Sample with the name of your Xamarin.Android project namespace.

using System;
using Android.App;
using Android.Runtime;
using Java.Interop;

namespace Sample
{
    [Register("android/support/multidex/MultiDexApplication", DoNotGenerateAcw = true)]
    public class MultiDexApplication : Application
    {
        internal static readonly JniPeerMembers _members =
        new XAPeerMembers("android/support/multidex/MultiDexApplication", typeof (MultiDexApplication));

        internal static IntPtr java_class_handle;

        private static IntPtr id_ctor;

        [Register(".ctor", "()V", "", DoNotGenerateAcw = true)]
        public MultiDexApplication()
        : base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
        {
            if (Handle != IntPtr.Zero)
                return;

            try
            {
                if (GetType() != typeof (MultiDexApplication))
                {
                    SetHandle(
                        JNIEnv.StartCreateInstance(GetType(), "()V"),
                        JniHandleOwnership.TransferLocalRef);
                        JNIEnv.FinishCreateInstance(Handle, "()V");
                    return;
                }

                if (id_ctor == IntPtr.Zero)
                    id_ctor = JNIEnv.GetMethodID(class_ref, "<init>", "()V");
                SetHandle(
                    JNIEnv.StartCreateInstance(class_ref, id_ctor),
                    JniHandleOwnership.TransferLocalRef);
                JNIEnv.FinishCreateInstance(Handle, class_ref, id_ctor);
            }
            finally
            {
            }
        }

        protected MultiDexApplication(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
        }

        internal static IntPtr class_ref
        {
            get { return JNIEnv.FindClass("android/support/multidex/MultiDexApplication", ref java_class_handle); }
        }

        protected override IntPtr ThresholdClass
        {
            get { return class_ref; }
        }

        protected override Type ThresholdType
        {
            get { return typeof (MultiDexApplication); }
        }
    }
}

Code source here.

If you are developing in Visual Studio for Windows, there is also a bug in the Android SDK build tools that you need to fix in order to properly create the classes.dex files when building your project.

Go to your Android SDK folder, open the build-tools folder and there will be folders with the numbers of the Android SDK compilers, such as:

C:\android-sdk\build-tools\23.0.3\

C:\android-sdk\build-tools\24.0.1\

C:\android-sdk\build-tools\25.0.2\

Inside each of those folders, there is a file called mainClassesDex.bat, a batch script used to create the classes.dex files. Open each mainClassesDex.bat file with a text editor (Notepad or Notepad++) and in its script, find and replace the block:

if DEFINED output goto redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder "%disableKeepAnnotated%" "%tmpJar%" "%params%"
goto afterClassReferenceListBuilder
:redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder "%disableKeepAnnotated%" "%tmpJar%" "%params%" 1>"%output%"
:afterClassReferenceListBuilder

With the block:

SET params=%params:'=%  
if DEFINED output goto redirect  
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder %disableKeepAnnotated% "%tmpJar%" %params%  
goto afterClassReferenceListBuilder  
:redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder %disableKeepAnnotated% "%tmpJar%" %params% 1>"%output%"  
:afterClassReferenceListBuilder

Source here.

Save each mainClassesDex.bat in the text editor after changes.

After the steps above, you should be able to successfully build your Xamarin.Android app with MultiDex.