I have a problem using my own MvvmCross plugins in an Android project, because the PluginLoader
seems to expect a .Droid.dll
of the exact namespace it is in.
Say I have three projects with this folder and namespace structure:
MyApp.Core:
Plugins/Settings/ISettings.cs
Plugins/Settings/PluginLoader.cs
MyApp.Droid:
Plugins/Settings/Settings.cs
Plugins/Settings/Plugin.cs
Bootstrap/SettingsPluginBootstrap.cs
MyApp.Touch:
Plugins/Settings/Settings.cs
Plugins/Settings/Plugin.cs
Bootstrap/SettingsPluginBootstrap.cs
The iOS project works just as expected, and finds the plugin without problem.
The Droid project on the other hand, fails with an exception: Could not load file or assembly 'MyApp.Plugins.Settings.Droid.dll' or one of its dependencies.
If I change the namespace of the PluginLoader
from MyApp.Core.Plugins.Settings
to simply MyApp
, the plugin works; I guess it looks for the MyApp.dll
and finds it. However, if I have multiple plugins in my app, they should each have their own namespace, they can't all be in the MyApp
namespace.
Currently the only workaround I have found is to create a separate project for each plugin I create, though this feels a bit unnecessary.
Why does the PluginLoader
insist on looking for the <PluginLoader namespace>.Droid.dll
file on Android, when the PluginLoader
on iOS finds the plugin without any problem?
MvvmCross plugins are designed to work as an assembly based layer on top of IoC.
By using a shared pattern for namespaces and assemblies, along with a couple of helper classes (Plugin and PluginLoader), plugins provide a way to share and reuse portable native code components.
The reason why iOS (and Mac) use a slightly different plugin loading scheme is because the MonoTouch's AoT compiler will not allow dynamic Assembly.Load
loading.
Because of this iOS has to use a different type of PluginManager
and a different type of Bootstrap
class to the other platforms. There's a bit more info on this in "How plugins are loaded" in https://github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins#how-plugins-are-loaded
If you wanted to add the Loader
type plugin registry to Android as well as iOS, then I think you could do this in a custom PluginManager
class and could then create this during Setup using an override of protected override IMvxPluginManager CreatePluginManager()
.
Something like:
public class MyPluginManager : MvxFilePluginManager, IMvxLoaderPluginManager
{
private readonly Dictionary<string, Func<IMvxPlugin>> _finders = new Dictionary<string, Func<IMvxPlugin>>();
public MyPluginManager(string platformDllPostfix, string assemblyExtension = "") : base(platformDllPostfix, assemblyExtension)
{
}
public IDictionary<string, Func<IMvxPlugin>> Finders
{
get { return _finders; }
}
protected override IMvxPlugin FindPlugin(Type toLoad)
{
var pluginName = toLoad.Namespace;
if (string.IsNullOrEmpty(pluginName))
{
throw new MvxException("Invalid plugin type {0}", toLoad);
}
Func<IMvxPlugin> finder;
if (_finders.TryGetValue(pluginName, out finder))
{
return finder();
}
return base.FindPlugin(toLoad);
}
}
initialised in your Setup using:
protected override IMvxPluginManager CreatePluginManager()
{
return new MyPluginManager(".Droid", ".dll");
}
you would then need to ensure that your loader
based plugins uses bootstrap classes based off of MvxLoaderPluginBootstrapAction
and not MvxPluginBootstrapAction
As another alternative, if you are not interested in reusing your plugins individually - if you would rather not ship lots of individual plugin assemblies - then you could put all your interfaces and implementations into one single assembly - and they could then share a single Bootstrap
, Plugin
and PluginLoader
between them.
As a final alternative, for your custom needs, you can always consider using your own custom bootstrap classes - the standard Setup
will create and Run
any constructable class in your UI assembly which implements IMvxBootstrapAction
- so you could replace SettingsPluginBootstrap
with some custom Run
action that suits your apps needs.
public class SettingsBootstrapAction
: IMvxBootstrapAction
{
public void Run()
{
// my stuff here
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With