How to include assets / resources in a Swift Package Manager library?

为君一笑 提交于 2019-11-30 16:54:45

The package manager does not yet have any definition for how resources will be bundled with targets. We are aware of the need for this, but don't yet have a concrete proposal for it. I filed https://bugs.swift.org/browse/SR-2866 to ensure we have a bug tracking this.

Due to framework bundles not being supported yet, the only way to provide bundle assets with an SPM target is through a Bundle. If you implement code in your framework to search for a particular bundle in your main project (supporting asset bundles), you can load resources from said bundle.

Example:

Access the bundled resources:

extension Bundle {
    static func myResourceBundle() throws -> Bundle {
        let bundles = Bundle.allBundles
        let bundlePaths = bundles.compactMap { $0.resourceURL?.appendingPathComponent("MyAssetBundle", isDirectory: false).appendingPathExtension("bundle") }

        guard let bundle = bundlePaths.compactMap({ Bundle(url: $0) }).first else {
            throw NSError(domain: "com.myframework", code: 404, userInfo: [NSLocalizedDescriptionKey: "Missing resource bundle"])
        }
        return bundle
    }
}

Utilize the Bundled resources:

        let bundle = try! Bundle.myResourceBundle()
        return UIColor(named: "myColor", in: bundle, compatibleWith: nil)!

You can apply the same logic for all resource files, including but not limited to storyboards, xibs, images, colors, data blobs, and files of various extensions (json, txt, etc).

Note: Sometimes this makes sense, sometimes it doesn't. Determine use to own project's discretion. It would take very specific scenarios to justify separating Storyboards/Xibs into bundled assets.

You can also load individual resources dynamically.

Suppose your packages test need some mock JSON data. You'd place the mock JSON files in a Tests/JSONMocks directory. Then in Package.swift:

targets: [
    .testTarget(
        name: "MyTargetTests",
        dependencies: ["MyTarget"],
        path: "Tests"
    ),
]

And load them dynamically:

static func dataForJSONFileNamed(string: String) -> Data {
    // find mock JSON files if using Swift Package Manager:
    let currentDirectoryURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
    let fileURL = currentDirectoryURL
        .appendingPathComponent("Tests", isDirectory: true)
        .appendingPathComponent("JSONMocks", isDirectory: true)
        .appendingPathComponent(string)
        .appendingPathExtension("json")
    let jsonFileData = try! Data(contentsOf: fileURL)
    return jsonFileData
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!