如何在不编译 DLL 的情况下在 Android 中使用 MvvmCross 插件?

Gei*_*erg 5 mvvmcross xamarin

我在 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
Run Code Online (Sandbox Code Playgroud)

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文件,PluginLoader在iOS上找插件没问题?

Stu*_*art 4

MvvmCross 插件被设计为作为 IoC 之上的基于程序集的层。

通过使用命名空间和程序集的共享模式以及几个帮助器类(Plugin 和 PluginLoader),插件提供了一种共享和重用可移植本机代码组件的方法。

iOS(和Mac)之所以使用稍微不同的插件加载方案,是因为MonoTouch的AoT编译器不允许动态Assembly.Load加载。

因此,iOS 必须使用PluginManagerBootstrap其他平台不同类型的类。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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令在您的设置中进行初始化:

    protected override IMvxPluginManager CreatePluginManager()
    {
        return new MyPluginManager(".Droid", ".dll");
    }
Run Code Online (Sandbox Code Playgroud)

然后,您需要确保您的loader基础插件使用基于MvxLoaderPluginBootstrapAction而不是基于的引导类MvxPluginBootstrapAction


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


作为最后的替代方案,对于您的自定义需求,您始终可以考虑使用自己的自定义引导类 - 标准SetupRun在您的 UI 程序集中创建并实现任何可构造的类IMvxBootstrapAction- 因此您可以替换为一些适合您的应用程序需求的SettingsPluginBootstrap自定义操作。Run

public class SettingsBootstrapAction
    : IMvxBootstrapAction
{
    public void Run()
    {
        // my stuff here
    }
}
Run Code Online (Sandbox Code Playgroud)