【问题标题】:How to use MvvmCross plugins in Android without compiling DLL?如何在不编译 DLL 的情况下在 Android 中使用 MvvmCross 插件?
【发布时间】:2013-11-15 22:18:48
【问题描述】:

我在 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在Android上坚持寻找<PluginLoader namespace>.Droid.dll文件,而在iOS上PluginLoader找到插件没有问题?

【问题讨论】:

  • 感谢您提出一个有趣的问题 - 我认为您正在探索的空间与当前使用插件的区域略有不同(但有共享区域)。我非常喜欢核心项目的想法,尽管它能够以某种方式为 ui 项目定义“合同” - 所以将其记录为一个想法 - github.com/MvvmCross/MvvmCross/issues/496

标签: xamarin mvvmcross


【解决方案1】:

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 的引导类


作为另一种选择,如果您对单独重用插件不感兴趣-如果您不想发布大量单独的插件程序集-那么您可以将所有接口和实现放入一个程序集中-然后它们可以共享一个单个BootstrapPluginPluginLoader


作为最后一种选择,对于您的自定义需求,您始终可以考虑使用您自己的自定义引导类 - 标准 Setup 将在您的 UI 程序集中创建和 Run 任何可构造的类,它实现了 IMvxBootstrapAction - 所以您可以将 SettingsPluginBootstrap 替换为适合您应用需求的一些自定义 Run 操作。

public class SettingsBootstrapAction
    : IMvxBootstrapAction
{
    public void Run()
    {
        // my stuff here
    }
}

【讨论】:

  • 感谢您提供许多可行的替代方案,我想我现在更了解插件了。目前我在Setup.cs 中覆盖InitializePlatformServices 并使用例如注册插件。 Mvx.ConstructAndRegisterSingleton&lt;ISettings, Settings&gt;(),虽然保留了iOS的默认插件行为,但感觉有点乱;混合插件模式和 IoC 容器。
猜你喜欢
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-03
  • 2015-12-17
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多