Linker Configuration In MugenMvvm

As we mentioned in Miscellaneous Startup Performance Tuning by design MugenMvvm is scanning all assemblies in order to match viewmodel->view and caching all needed types.

Along with usage of IBootstrapCodeBuilder interface to decrease startup time you can use linker to decrease the size of release application.
The MugenMvvm linker share the same idea as platform-specific linker on Xamarin (Android, iOS).

Let's see on Android example. As our application we will take our HelloLinker app. Clone it on your PC and open the solution. Restore all nuget packages in HelloLinker. In order to restore Net Standard libs in "Core" project try to reinstall them.

19201920

HelloLinker android app.

In "HelloLinker" project properties is setted Linker -> "Sdk Assemblies Only" as long as "Release" build configuration is setted in solution properties.

19201920

Let's build application and check the size of apk file:

574574

App size before optimization

As you can see, the size of app is 12.9 Mb.

Instead of using dynamic loading of modules static loading can be applied to reduce the app size. Linker configuration consists of two steps:

  1. Get code that binds attached members.
  2. Override LoadModules in App and pass static loaders into it.

Here we have to statically bind all attached members we need.
Add new constructor in "App.cs" and override the LoadModules method:

using System;
using System.Collections.Generic;
using System.Reflection;
using Core.ViewModels;
using MugenMvvmToolkit;
using MugenMvvmToolkit.Interfaces.Models;

namespace Core
{
    public class App : MvvmApplication
    {
        private readonly Action<IModuleContext> _loadModulesDelegate;

        public App(Action<IModuleContext> loadModulesDelegate = null)
        {
            _loadModulesDelegate = loadModulesDelegate;
        }

        protected override void LoadModules(IList<Assembly> assemblies)
        {
            if (_loadModulesDelegate == null)
                base.LoadModules(assemblies);
            else
                _loadModulesDelegate(CreateModuleContext(assemblies));
        }

        #region Overrides of MvvmApplication

        public override Type GetStartViewModelType()
        {
            return typeof(MainViewModel);
        }

        #endregion
    }
}

Now we have to create a class which will register all needed attached members statically. By default all attached members is registered by special platform-specific class. On Android platform this class is AndroidDataBindingModule. Let's create our own light version of this class. Create new class with next content in "HelloLinker" project:

using MugenMvvmToolkit;
using MugenMvvmToolkit.Android;
using MugenMvvmToolkit.Android.Binding.Infrastructure;
using MugenMvvmToolkit.Binding;
using MugenMvvmToolkit.Binding.Behaviors;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.Models;
using MugenMvvmToolkit.Models;
using AttachedMembersRegistration = MugenMvvmToolkit.Android.Binding.AttachedMembersRegistration;

namespace HelloLinker.Modules
{
  public class LightAndroidDataBindingModule : IModule
  {
    #region Properties

      public int Priority => ApplicationSettings.ModulePriorityInitialization + 1;

    #endregion

      #region Implementation of interfaces

      public bool Load(IModuleContext context)
    {
      if (context.PlatformInfo.Platform == PlatformType.Android)
      {
        BindingServiceProvider.Initialize(errorProvider: new AndroidBindingErrorProvider());
        BindingServiceProvider.BindingProvider.DefaultBehaviors.Add(DisableEqualityCheckingBehavior.TargetTrueNotTwoWay);
      }

      PlatformExtensions.ItemsSourceAdapterFactory = (o, ctx, arg3) => new ItemsSourceAdapter(o, ctx, true);

      AttachedMembersRegistration.RegisterObjectMembers();
      AttachedMembersRegistration.RegisterViewBaseMembers();
      AttachedMembersRegistration.RegisterViewMembers();
      AttachedMembersRegistration.RegisterTextViewMembers();
      AttachedMembersRegistration.RegisterViewGroupMembers();
      // here we not include unnecessary attached members
            //AttachedMembersRegistration.RegisterAutoCompleteTextViewMembers();
      //AttachedMembersRegistration.RegisterDatePickerMembers();
      //AttachedMembersRegistration.RegisterTimePickerMembers();
      // another commented out attached members
      return true;
    }

    public void Unload(IModuleContext context)
    {
    }

    #endregion
  }
}

Now, pass delegate to load assemblies in App:

using HelloLinker;
using MugenMvvmToolkit;
using MugenMvvmToolkit.Android.Attributes;
using MugenMvvmToolkit.Android.Infrastructure;
using MugenMvvmToolkit.Interfaces;

[assembly: Bootstrapper(typeof(Setup))]

namespace HelloLinker
{
    public class Setup : AndroidBootstrapperBase
    {
        #region Overrides of AndroidBootstrapperBase

        protected override IIocContainer CreateIocContainer()
        {
            return new AutofacContainer();
        }

        protected override IMvvmApplication CreateApplication()
        {
            return new Core.App(LoadModules);
        }

        #endregion

        private static void LoadModules(MugenMvvmToolkit.Interfaces.Models.IModuleContext context)
        {
            new LightAndroidDataBindingModule().Load(context);
            new MugenMvvmToolkit.Android.Modules
              .AndroidInitializationModule().Load(context);
          // new MugenMvvmToolkit.Android.Modules
          //.FragmentInitializationModule().Load(context);
          // new MugenMvvmToolkit.Android.Modules
          // .PreferenceInitializationModule().Load(context);
                    // new MugenMvvmToolkit.Android.Binding
          //.Modules.FragmentDataBindingModule().Load(context);
        }
    }
}

As you can see, here we commented out some modules that we are not using in our application. This is the way how you can control the size of application i.e. by removing unnecessary modules and attached members.
Now set "Linking" to "Sdk and User Assemblies" and add "Core", "HelloLinker" into skipping textbox:

19201920

Build the application and check the size of apk:

603603

App size after optimization.

As you can see app size is decreased from 12 Mb to 10 Mb.

The optimized version of "HelloLinker" app can be found on Github.

📘

Other platforms

This approach is available on each of supported platforms.