Как использовать плагины MvvmCross в Android без компиляции DLL?
Вопрос
У меня возникла проблема с использованием моих собственных плагинов MvvmCross в проекте Android, поскольку 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) использует немного другую схему загрузки плагинов, заключается в том, что AoT-компилятор MonoTouch не допускает динамического 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
любой конструируемый класс в вашей сборке пользовательского интерфейса, который реализует IMvxBootstrapAction
- чтобы вы могли заменить SettingsPluginBootstrap
с некоторыми обычаями Run
действие, которое соответствует потребностям ваших приложений.
public class SettingsBootstrapAction
: IMvxBootstrapAction
{
public void Run()
{
// my stuff here
}
}