Skip to content

Instantly share code, notes, and snippets.

@khorbushko
Created March 3, 2020 09:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khorbushko/bc5b4b3574101b00e56c091c31cdd683 to your computer and use it in GitHub Desktop.
Save khorbushko/bc5b4b3574101b00e56c091c31cdd683 to your computer and use it in GitHub Desktop.
Plist reader
import UIKit
// MARK: - URLScheme
public typealias URLScheme = String
// MARK: - URLType
public struct URLType: Codable {
public private (set) var role: String?
public private (set) var iconFile: String?
public private (set) var urlSchemes: [String]
// MARK: - Codable
private enum Key: String, CodingKey {
case role = "CFBundleTypeRole"
case iconFile = "CFBundleURLIconFile"
case urlSchemes = "CFBundleURLSchemes"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: URLType.Key.self)
role = try container.decode(String.self, forKey: .role)
iconFile = try container.decode(String.self, forKey: .iconFile)
urlSchemes = try container.decode([String].self, forKey: .urlSchemes)
}
}
// MARK: - InfoPlist
public struct InfoPlist: Codable {
public private (set) var displayName: String?
public private (set) var bundleId: String
public private (set) var bundleName: String?
public private (set) var versionNumber: String?
public private (set) var buildNumber: String?
public private (set) var urlTypes: [URLType]?
// MARK: - Codable
private enum Key: String, CodingKey {
case displayName = "CFBundleDisplayName"
case bundleName = "CFBundleName"
case bundleId = "CFBundleIdentifier"
case versionNumber = "CFBundleShortVersionString"
case buildNumber = "CFBundleVersion"
case urlTypes = "CFBundleURLTypes"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: InfoPlist.Key.self)
bundleId = try container.decode(String.self, forKey: .bundleId)
versionNumber = try container.decode(String.self, forKey: .versionNumber)
buildNumber = try container.decode(String.self, forKey: .buildNumber)
displayName = try? container.decodeIfPresent(String.self, forKey: .displayName)
bundleName = try? container.decodeIfPresent(String.self, forKey: .bundleName)
urlTypes = try? container.decodeIfPresent([URLType].self, forKey: .urlTypes)
}
}
// SOURCE: https://medium.com/ios-os-x-development/strongly-typed-access-to-info-plist-file-using-swift-50e78d5abf96
import Foundation
private enum Resource {
enum Extension {
static let plist = "plist"
}
}
// A class to read and decode strongly typed values in `plist` files.
public class PListFile<T: Codable> {
/// Errors.
///
/// - fileNotFound: plist file not exists.
public enum Errors: Error {
case fileNotFound
}
/// Plist file source.
///
/// - infoPlist: main bundel's Info.plist file
/// - plist: other plist file with custom name
public enum Source {
case infoPlist(bundle: Bundle)
case plist(name: String, bundle: Bundle)
/// Get the raw data inside given plist file.
///
/// - Returns: read data
/// - Throws: throw an exception if it fails
internal func data() throws -> Data {
switch self {
case .infoPlist(let bundle):
guard let infoDict = bundle.infoDictionary else {
throw Errors.fileNotFound
}
return try JSONSerialization.data(withJSONObject: infoDict)
case .plist(let filename, let bundle):
guard let path = bundle.path(forResource: filename, ofType: Resource.Extension.plist) else {
throw Errors.fileNotFound
}
return try Data(contentsOf: URL(fileURLWithPath: path))
}
}
}
/// Data read for file
public let data: T
/// Initialize a new Plist parser with given codable structure.
///
/// - Parameter file: source of the plist
/// - Throws: throw an exception if read fails
public init(_ file: PListFile.Source = .infoPlist(bundle: Bundle.main)) throws {
let rawData = try file.data()
let decoder = JSONDecoder()
self.data = try decoder.decode(T.self, from: rawData)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment