对此的解决方案并不简单,但也不是不可能。我更愿意使用swift包管理器来管理依赖项,并将Xcode作为IDE进行管理。这种组合并不完美,因为它需要大量修补,但目前还没有任何其他可用的免费swift IDE。
您将需要设立两个项目,我们姑且称之为插件(第三方库)和PluginConsumer(应用程序使用其他人的插件)。您还需要在API决定,现在我们将使用简单的
TestPluginFunc()
创建Plugin.swift与TestPluginFunc实现文件在您的插件项目:
public func TestPluginFunc() {
print("Hooray!")
}
将项目建设框架,不可执行并生成[1]。你将得到包含你的插件的Plugin.framework文件。
现在切换到你的PluginConsumer项目
复制Plugin.framework从插件项目的地方在那里,你可以很容易地找到它。要实际加载框架并使用它:
// 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")
}
}
如果操作正确,您应该看到“Hooray!“
有很大的改进空间,你应该做的第一件事是用参数替换Plugin.framework字符串,最好使用一些文件库(我正在使用PerfectLib)。在您的PluginConsumer项目中定义插件API作为协议或基类,创建框架,在您的插件项目中导入该框架,并将您的实现基于该协议/基类。我试图弄清楚如何做。如果我奶源正确做到这一点,我会更新这个帖子
[1]:我通常通过创建Package.swift文件和创建Xcode项目出它使用swift package generate-xcodeproj
的做到这一点。如果你的项目没有。包含main.sw ift,xcode将创建框架而不是可执行文件