Skip to content

Instantly share code, notes, and snippets.

@bscothern
Created August 6, 2021 19:46
Show Gist options
  • Save bscothern/8a7e2d868196dffa83a5c9d03f4ca57c to your computer and use it in GitHub Desktop.
Save bscothern/8a7e2d868196dffa83a5c9d03f4ca57c to your computer and use it in GitHub Desktop.
SwiftPM Bundle Finding
////////////////////////////////////
// Main bundle finding logic
import Foundation
public protocol BundleFinder: AnyObject {
static var packageName: String { get }
static var moduleName: String { get }
static var packageModule: Bundle { get }
}
extension Bundle {
private static var foundBundles: [String: Bundle] = [:]
public static func bundleFinder(_ finder: BundleFinder.Type) -> Bundle {
#if !DEBUG
return finder.packageModule
#else
let bundleName = "\(finder.packageName)_\(finder.moduleName).bundle"
if let bundle = foundBundles[bundleName] {
return bundle
}
let candidates = [
// Main app bundle
Bundle.main.resourceURL,
// Framework bundle location
Bundle(for: finder.self).resourceURL,
// CLI
Bundle.main.bundleURL,
// iOS Previews
Bundle(for: finder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(),
// macOS Previews
Bundle(for: finder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent(),
]
for candidate in candidates {
let bundlePath = candidate?.appendingPathComponent(bundleName)
if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
foundBundles[finder.packageName] = bundle
return bundle
}
}
fatalError("Unable to find bundle: \(bundleName)")
#endif
}
}
////////////////////////////////////
// "Template" in each package module
import Foundation
extension Foundation.Bundle {
@usableFromInline
class _CurrentBundleFinder: BundleFinder {
@usableFromInline
static let packageName: String = "YourPackageName"
#if swift(<6.0)
@usableFromInline
static let moduleName: String = String(#fileID.split(separator: "/")[0])
#else
#error("Module name calculating not yet supported on Swift 6.0+")
#endif
@usableFromInline
static let packageModule: Bundle = .module
}
/// Use this instead of `.module` for finding resources.
@usableFromInline
internal static var package: Bundle { .bundleFinder(_CurrentBundleFinder.self) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment