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.
In "HelloLinker" project properties is setted Linker -> "Sdk Assemblies Only" as long as "Release" build configuration is setted in solution properties.
Let's build application and check the size of apk file:
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:
- Get code that binds attached members.
- Override
LoadModules
inApp
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:
Build the application and check the size of apk:
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.
Updated almost 8 years ago