Created
August 6, 2021 19:46
-
-
Save bscothern/8a7e2d868196dffa83a5c9d03f4ca57c to your computer and use it in GitHub Desktop.
SwiftPM Bundle Finding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////// | |
// 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