Plugins 如何在swift中创建插件

Plugins 如何在swift中创建插件,plugins,swift3,Plugins,Swift3,我发现了如何使用Swift和Cocoa创建插件。它使用NSBundle加载插件,但据我所知,这在纯swift中是不可用的(没有Cocoa)。有没有办法在不使用可可粉的情况下达到同样的效果 更多信息: 如果相关的话,以下是我想要实现的目标。我用在linux服务器上运行的swift创建应用程序。用户可以使用浏览器连接到它。我希望能够让其他人编写“插件”,实现自己的功能(用户连接后可以看到和执行的功能),从打印hello world,通过聊天程序到游戏,而不必担心我的应用程序提供的低级内容。我的服务器

我发现了如何使用Swift和Cocoa创建插件。它使用NSBundle加载插件,但据我所知,这在纯swift中是不可用的(没有Cocoa)。有没有办法在不使用可可粉的情况下达到同样的效果

更多信息:


如果相关的话,以下是我想要实现的目标。我用在linux服务器上运行的swift创建应用程序。用户可以使用浏览器连接到它。我希望能够让其他人编写“插件”,实现自己的功能(用户连接后可以看到和执行的功能),从打印hello world,通过聊天程序到游戏,而不必担心我的应用程序提供的低级内容。我的服务器应用程序加载并运行的某种dll

您要做的是创建一个文件夹,让程序在其中查找。比方说它叫“插件”。它应该从其中的文件中创建一个名称列表,然后使用它们进行迭代,将参数传递给文件,获得输出,并以某种方式使用这些文件

:

`

以下是swift插件如何接受参数:

    for i in 1..C_ARGC {
    let index = Int(i);

    let arg = String.fromCString(C_ARGV[index])
       switch arg {
        case 1:
            println("1");

        case 2:
            println("2")

        default:
            println("3)
       }
    }

因此,一旦程序和插件进行了通信,您只需根据输出在程序中添加处理,这样插件输出就可以做一些有意义的事情。如果没有cocoa库,这似乎是一种方法,但是如果使用C,也有一些其他选项可用。希望这有帮助

解决这个问题的方法并不简单,但也不是不可能做到的。我更喜欢使用swift软件包管理器来管理依赖项和作为IDE的Xcode。这种组合并不完美,因为它需要大量的修改,但目前还没有其他可用的免费swift IDE

您将需要设置两个项目,我们将它们称为Plugin(第三方库)和pluginCustomer(使用其他人插件的应用程序)。您还需要决定API,因为现在我们将使用simple

TestPluginFunc()
在您的Plugin项目中创建Plugin.swift文件和TestPluginFunc实现:

public func TestPluginFunc() {
    print("Hooray!")
}
将项目设置为生成框架,而不是可执行和生成[1]。您将获得Plugin.framework文件,其中包含您的插件

现在切换到您的pluginumer项目

将Plugin.framework从您的Plugin项目复制到您可以轻松找到它的地方。要实际加载并使用框架,请执行以下操作:

// we need to define how our plugin function looks like
typealias TestPluginFunc = @convention(c) ()->()
// and what is its name
let pluginFuncName = "TestPluginFunc"

func loadPlugin() {
    let pluginName = "Plugin"
    let openRes = dlopen("./\(pluginName).framework/\(pluginName)", RTLD_NOW|RTLD_LOCAL)
    if openRes != nil {
        // this is fragile
        let symbolName = "_TF\(pluginName.utf8.count)\(pluginName)\(initFuncName.utf8.count)\(initFuncName)FT_T_"
        let sym = dlsym(openRes, symbolName)
        if sym != nil {
            // here we load func from framework based on the name we constructed in "symbolName" variable
            let f: TestPluginFunc = unsafeBitCast(sym, to: TestPluginFunc.self)

            // and now all we need to do is execute our plugin function
            f()

        } else {
            print("Error loading \(realPath). Symbol \(symbolName) not found.")
            dlclose(openRes)
        }
    } else {
        print("error opening lib")
    }
}
如果操作正确,您应该会看到“万岁!”打印到日志中

还有很大的改进空间,首先应该用参数替换Plugin.framework字符串,最好使用一些文件库(我使用的是PerfectLib)。另一件需要注意的事情是,在PluginConsumer项目中将pluginAPI定义为协议或基类,在此基础上创建框架,在plugin项目中导入该框架,并将实现基于该协议/基类。我正试图弄清楚如何做到这一点。我会更新这篇文章,如果我管理做得好

[1] :我通常通过创建Package.swift文件并使用
swift Package generate xcodeproj
从中创建xcode项目来实现这一点。如果您的项目不包含main.swift,xcode将创建框架而不是可执行文件

// we need to define how our plugin function looks like
typealias TestPluginFunc = @convention(c) ()->()
// and what is its name
let pluginFuncName = "TestPluginFunc"

func loadPlugin() {
    let pluginName = "Plugin"
    let openRes = dlopen("./\(pluginName).framework/\(pluginName)", RTLD_NOW|RTLD_LOCAL)
    if openRes != nil {
        // this is fragile
        let symbolName = "_TF\(pluginName.utf8.count)\(pluginName)\(initFuncName.utf8.count)\(initFuncName)FT_T_"
        let sym = dlsym(openRes, symbolName)
        if sym != nil {
            // here we load func from framework based on the name we constructed in "symbolName" variable
            let f: TestPluginFunc = unsafeBitCast(sym, to: TestPluginFunc.self)

            // and now all we need to do is execute our plugin function
            f()

        } else {
            print("Error loading \(realPath). Symbol \(symbolName) not found.")
            dlclose(openRes)
        }
    } else {
        print("error opening lib")
    }
}