Using Swift Package Manager resources with Carthage/CocoaPods
As of Swift 5.3, Swift Package Manager now supports bundling resources with your package. This has been a blocker to adopting SwiftPM for us as we have a number of dependencies that require resources.
I’ve been happily using Carthage for years, but with some Xcode 12 issues and no XCFrameworks/Catalyst support, it seemed like a good time to give SwiftPM another shot. It turns out adding and using resources is really straight-forward, you just need to add a resource declaration to your target as as documented here.
When using that resource, you look it up via Bundle.module
like so:
Bundle.module.url(forResource: "settings", withExtension: "json")
But there is one gotcha, which is that Bundle.module
is only defined when building via SwiftPM. If you want to continue to support Carthage/CocoaPods and need to reference that resource internally, you can’t use Bundle.module
. I couldn’t find a solution in the docs, so I lazy tweeted and luckily @neonacho (who just happens to work on Swift Package Manager) replied with the answer.
Turns out SwiftPM defines a preprocessor definition of SWIFT_PACKAGE
, which later I found documented here. Now we can know at compile time whether we’re in a package and can condition our logic based on that and return the correct bundle:
static var bundle: Bundle {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: SomeFrameworkClass.self)
#endif
}