FakeBundle

🗄 在 Swift Package Manager 可执行文件中使用资源

描述

由于 Swift Package Manager 不支持 Swift 可执行文件的资源或 Bundle,我需要一种方法来集成通用文件资源(包括文件夹结构)到我的二进制文件中。

FakeBundle 接收一个输入文件夹并生成一个单独的代码文件,该文件可用于在运行时将整个文件夹或单个文件导出到文件系统。

Mint 🌱 一起使用

$ 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 许可证发布。