🗄 在 Swift Package Manager 可执行文件中使用资源
由于 Swift Package Manager 不支持 Swift 可执行文件的资源或 Bundle
,我需要一种方法来集成通用文件资源(包括文件夹结构)到我的二进制文件中。
FakeBundle
接收一个输入文件夹并生成一个单独的代码文件,该文件可用于在运行时将整个文件夹或单个文件导出到文件系统。
$ mint run zweigraf/FakeBundle fakebundle --input ./Resources --output ./Resources.swift
假设你有一个模板文件夹,但想将你的应用程序作为单个二进制文件分发(或以其他方式简化安装)。你可以将所有这些模板作为字符串添加到你的代码中,但这维护起来会很麻烦。在这种情况下,你可以运行 FakeBundle
作为预编译脚本阶段,并自动生成一个包含所有模板的类。在运行时,你可以将模板导出回文件系统,或直接从代码中使用它们。
我的主要用例是将整个输入文件夹直接导出回文件系统。可以像这样完成(Resources
这里是顶层输入文件夹的名称)
Resources().export(to: <path>)
这将在磁盘上的 <path>
中创建 Resources 文件夹,并将所有子项递归地导出到其中。单个文件也可以导出,但现在获取对它们的引用非常麻烦(遍历子项)。
目前你无法直接轻松访问文件。
Resources().children.forEach {
if $0.isDirectory {
// Special directory handling
} else if let file = $0 as? File {
if file.filename == "MyImage.png",
let data = file.contents,
let image = UIImage(data: data) {
// You now have an image
}
}
}
生成的代码符合以下协议(这些协议包含在生成的资源文件中)
protocol FileType {
var isDirectory: Bool { get }
var filename: String { get }
func export(to path: String) throws
}
protocol File: FileType {
var contentsBase64: String { get }
}
extension File {
var isDirectory: Bool {
return false
}
var contents: Data? {
return Data(base64Encoded: contentsBase64)
}
func export(to path: String) throws {
guard let contents = contents else { return }
let originalUrl = URL(fileURLWithPath: path)
let myUrl = originalUrl.appendingPathComponent(filename)
try contents.write(to: myUrl)
}
}
protocol Directory: FileType {
var children: [FileType] { get }
}
extension Directory {
var isDirectory: Bool {
return true
}
func export(to path: String) throws {
let originalUrl = URL(fileURLWithPath: path)
let myUrl = originalUrl.appendingPathComponent(filename)
try FileManager.default.createDirectory(at: myUrl, withIntermediateDirectories: true, attributes: nil)
try children.forEach { try $0.export(to: myUrl.path) }
}
}
FakeBundle 基于 MIT 许可证发布。