import Foundation struct InfoPlistReader { private enum Keys { static let baseBundleIdentifier = "baseBundleIdentifier" static let keychainAccessGroupIdentifier = "keychainAccessGroupIdentifier" static let bundleDisplayName = "CFBundleDisplayName" } /// Info.plist reader on the bundle object that contains the current executable. static let main = InfoPlistReader(bundle: .main) /// Info.plist reader on the bundle object that contains the main app executable. static let app = InfoPlistReader(bundle: .app) private let bundle: Bundle /// Initializer /// - Parameter bundle: bundle to read values from init(bundle: Bundle) { self.bundle = bundle } /// Base bundle identifier set in Info.plist of the target var baseBundleIdentifier: String { infoPlistValue(forKey: Keys.baseBundleIdentifier) } /// Keychain access group identifier set in Info.plist of the target var keychainAccessGroupIdentifier: String { infoPlistValue(forKey: Keys.keychainAccessGroupIdentifier) } /// Bundle display name of the target var bundleDisplayName: String { infoPlistValue(forKey: Keys.bundleDisplayName) } private func infoPlistValue(forKey key: String) -> T { guard let result = bundle.object(forInfoDictionaryKey: key) as? T else { fatalError("Add \(key) into your target's Info.plst") } return result } }