Beam/ElementX/Sources/Other/InfoPlistReader.swift
Doug 6ded867bcc
Configure diagnostics (and MapLibre) using Pkl. (#3820)
* Bump the version for the next release.

* Ignore all generated sources.

* Use Pkl+XcodeGen to inject secrets instead of the project.

* Inject the PostHog/Sentry/Rageshake configuration from the environment.

* Fix bad unicode.

* Fix unit tests.
2025-02-24 18:36:08 +00:00

133 lines
4.4 KiB
Swift

//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Foundation
struct InfoPlistReader {
private enum Keys {
static let appGroupIdentifier = "appGroupIdentifier"
static let baseBundleIdentifier = "baseBundleIdentifier"
static let keychainAccessGroupIdentifier = "keychainAccessGroupIdentifier"
static let bundleShortVersion = "CFBundleShortVersionString"
static let bundleDisplayName = "CFBundleDisplayName"
static let productionAppName = "productionAppName"
static let utExportedTypeDeclarationsKey = "UTExportedTypeDeclarations"
static let utTypeIdentifierKey = "UTTypeIdentifier"
static let utDescriptionKey = "UTTypeDescription"
static let bundleURLTypes = "CFBundleURLTypes"
static let bundleURLName = "CFBundleURLName"
static let bundleURLSchemes = "CFBundleURLSchemes"
}
private enum Values {
static let mentionPills = "Mention Pills"
}
/// 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
}
/// App group identifier set in Info.plist of the target
var appGroupIdentifier: String {
infoPlistValue(forKey: Keys.appGroupIdentifier)
}
/// 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 executable of the target
var bundleExecutable: String {
infoPlistValue(forKey: kCFBundleExecutableKey as String)
}
/// Bundle identifier of the target
var bundleIdentifier: String {
infoPlistValue(forKey: kCFBundleIdentifierKey as String)
}
/// Bundle short version string of the target
var bundleShortVersionString: String {
infoPlistValue(forKey: Keys.bundleShortVersion)
}
/// Bundle version of the target
var bundleVersion: String {
infoPlistValue(forKey: kCFBundleVersionKey as String)
}
/// Bundle display name of the target
var bundleDisplayName: String {
infoPlistValue(forKey: Keys.bundleDisplayName)
}
/// The name of the non-X app when it becomes production ready.
var productionAppName: String {
infoPlistValue(forKey: Keys.productionAppName)
}
// MARK: - Custom App Scheme
var appScheme: String {
customSchemeForName("Application")
}
var elementCallScheme: String {
customSchemeForName("Element Call")
}
// MARK: - Mention Pills
/// Mention Pills UTType
var pillsUTType: String {
let exportedTypes: [[String: Any]] = infoPlistValue(forKey: Keys.utExportedTypeDeclarationsKey)
guard let mentionPills = exportedTypes.first(where: { $0[Keys.utDescriptionKey] as? String == Values.mentionPills }),
let utType = mentionPills[Keys.utTypeIdentifierKey] as? String else {
fatalError("Add properly \(Values.mentionPills) exported type into your target's Info.plst")
}
return utType
}
// MARK: - Private
private func infoPlistValue<T>(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
}
private func customSchemeForName(_ name: String) -> String {
let urlTypes: [[String: Any]] = infoPlistValue(forKey: Keys.bundleURLTypes)
guard let urlType = urlTypes.first(where: { $0[Keys.bundleURLName] as? String == name }),
let urlSchemes = urlType[Keys.bundleURLSchemes] as? [String],
let scheme = urlSchemes.first else {
fatalError("Invalid custom application scheme configuration")
}
return scheme
}
}