如何在Android中使用MvvmCross插件而不编译DLL?
题
我在 Android 项目中使用自己的 MvvmCross 插件时遇到问题,因为 PluginLoader
似乎期待一个 .Droid.dll
它所在的确切命名空间。
假设我有三个具有此文件夹和命名空间结构的项目:
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
iOS 项目按预期工作,并且找到插件没有问题。
另一方面,Droid 项目因异常而失败: Could not load file or assembly 'MyApp.Plugins.Settings.Droid.dll' or one of its dependencies.
如果我更改的命名空间 PluginLoader
从 MyApp.Core.Plugins.Settings
简单地 MyApp
, ,插件有效;我猜它正在寻找 MyApp.dll
并找到它。但是,如果我的应用程序中有多个插件,它们应该每个都有自己的命名空间,它们不能全部位于 MyApp
命名空间。
目前我发现的唯一解决方法是为我创建的每个插件创建一个单独的项目,尽管这感觉有点不必要。
为什么 PluginLoader
坚持寻找 <PluginLoader namespace>.Droid.dll
Android 上的文件,当 PluginLoader
在iOS上发现插件没有任何问题?
解决方案
MvvmCross 插件被设计为作为 IoC 之上的基于程序集的层。
通过使用命名空间和程序集的共享模式以及几个帮助器类(Plugin 和 PluginLoader),插件提供了一种共享和重用可移植本机代码组件的方法。
iOS(和Mac)使用稍微不同的插件加载方案的原因是MonoTouch的AoT编译器不允许动态 Assembly.Load
加载中。
因此 iOS 必须使用不同类型的 PluginManager
以及不同类型的 Bootstrap
类到其他平台。在“如何加载插件”中有更多关于此的信息 https://github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins#how-plugins-are-loaded
如果您想添加 Loader
在 Android 和 iOS 中输入插件注册表,然后我认为您可以在自定义中执行此操作 PluginManager
类,然后可以在安装过程中使用覆盖来创建它 protected override IMvxPluginManager CreatePluginManager()
.
就像是:
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);
}
}
使用以下命令在您的设置中进行初始化:
protected override IMvxPluginManager CreatePluginManager()
{
return new MyPluginManager(".Droid", ".dll");
}
然后你需要确保你的 loader
基于插件使用基于引导类 MvxLoaderPluginBootstrapAction
并不是 MvxPluginBootstrapAction
作为另一种选择,如果您对单独重用插件不感兴趣 - 如果您不想发布大量单独的插件程序集 - 那么您可以将所有接口和实现放入一个程序集中 - 然后它们可以共享一个程序集 Bootstrap
, Plugin
和 PluginLoader
它们之间。
作为最后的选择,为了满足您的自定义需求,您始终可以考虑使用自己的自定义引导类 - 标准 Setup
将创造和 Run
UI 程序集中实现的任何可构造类 IMvxBootstrapAction
- 这样你就可以替换 SettingsPluginBootstrap
有一些习惯 Run
适合您的应用程序需求的操作。
public class SettingsBootstrapAction
: IMvxBootstrapAction
{
public void Run()
{
// my stuff here
}
}