import Foundation public extension Bundle { private final class Marker {} // Looking for bundle involves a lot of IO private static let cache: NSCache = NSCache() public static func resourcesBundle(forModuleName moduleName: String) -> Bundle { if let cachedBundle = cache.object(forKey: moduleName as NSString) { return cachedBundle } let bundle = resolved(forModuleName: moduleName) cache.setObject(bundle, forKey: moduleName as NSString) return bundle } private static func resolved(forModuleName moduleName: String) -> Bundle { return Bundle.main.anyNested(forModuleName: moduleName) ?? Bundle.main } private func anyNested(forModuleName moduleName: String) -> Bundle? { if let framework = nestedFramework(name: moduleName) { return framework.nestedResourceBundle(moduleName: moduleName) ?? framework } return nestedResourceBundle(moduleName: moduleName) } private func nestedFramework(name: String) -> Bundle? { return path(forResource: name, ofType: "framework", inDirectory: "Frameworks") .flatMap(Bundle.init(path:)) } private func nestedResourceBundle(moduleName: String) -> Bundle? { guard let resourceBundlePath = path(forResource: moduleName + "Resources", ofType: "bundle") ?? path(forResource: moduleName, ofType: "bundle") else { return nil } return Bundle(path: resourceBundlePath) } }