import Foundation final public class Device: NSObject { /// Creates an returns a new device object representing the current device @objc public static func makeCurrentDevice() -> Device { let platform = currentPlatform() let humanReadablePlatformName = humanReadablePlatformNameForCurrentDevice() let os = osVersionForCurrentDevice() let screenSize = screenSizeForCurrentDevice() let nativeScreenSize = nativeScreenSizeForCurrentDevice() return Device(platform: platform, humanReadablePlatformName: humanReadablePlatformName, osVersion: os, screenSize: screenSize, nativeScreenSize: nativeScreenSize) } /// The platform name of the device i.e. "iPhone1,1" or "iPad3,6" @objc public let platform: String /// A human readable version of the platform name i.e. "iPhone 6 Plus" or "iPad Air 2 (WiFi)" /// Will be nil if no human readable string was found. @objc public let humanReadablePlatformName: String? /// The version number of the OS as String i.e. "1.2" or "9.4" @objc public let osVersion: String /// The screen size @objc public let screenSize: CGSize /// The native screen size /// Will be CGSize.zero if the value is not defined on the running platorm. @objc public let nativeScreenSize: CGSize required public init(platform: String, humanReadablePlatformName: String? = nil, osVersion: String, screenSize: CGSize, nativeScreenSize: CGSize? = nil) { self.platform = platform self.humanReadablePlatformName = humanReadablePlatformName self.osVersion = osVersion self.screenSize = screenSize self.nativeScreenSize = nativeScreenSize != nil ? nativeScreenSize! : CGSize.zero super.init() } } extension Device { /// The platform name of the current device i.e. "iPhone1,1" or "iPad3,6" private static func currentPlatform() -> String { var size = 0 sysctlbyname("hw.machine", nil, &size, nil, 0) var machine = [CChar](repeating: 0, count: Int(size)) sysctlbyname("hw.machine", &machine, &size, nil, 0) return String(cString: machine) } /// Returns a human readable version of the current platform name i.e. "iPhone 6 Plus" or "iPad Air 2 (WiFi)" /// Will return nil, if no human readable string could be found for the current platform private static func humanReadablePlatformNameForCurrentDevice() -> String? { let platform = currentPlatform() switch platform { // iPhone case "iPhone1,1": return "iPhone 1G" case "iPhone1,2": return "iPhone 3G" case "iPhone2,1": return "iPhone 3GS" case "iPhone3,1": return "iPhone 4" case "iPhone3,2": return "iPhone 4 (Revision A)" case "iPhone3,3": return "Verizon iPhone 4" case "iPhone4,1": return "iPhone 4S" case "iPhone5,1": return "iPhone 5 (GSM)" case "iPhone5,2": return "iPhone 5 (GSM+CDMA)" case "iPhone5,3": return "iPhone 5c (GSM)" case "iPhone5,4": return "iPhone 5c (Global)" case "iPhone6,1": return "iPhone 5s (GSM)" case "iPhone6,2": return "iPhone 5s (Global)" case "iPhone7,1": return "iPhone 6 Plus" case "iPhone7,2": return "iPhone 6" case "iPhone8,1": return "iPhone 6s" case "iPhone8,2": return "iPhone 6s Plus" case "iPhone8,4": return "iPhone SE" case "iPhone9,1": return "iPhone 7 (GSM+CDMA)" case "iPhone9,2": return "iPhone 7 Plus (GSM+CDMA)" case "iPhone9,3": return "iPhone 7 (Global)" case "iPhone9,4": return "iPhone 7 Plus (Global)" case "iPhone10,1": return "iPhone 8 (GSM+CDMA)" case "iPhone10,2": return "iPhone 8 Plus (GSM+CDMA)" case "iPhone10,3": return "iPhone X (GSM+CDMA)" case "iPhone10,4": return "iPhone 8 (Global)" case "iPhone10,5": return "iPhone 8 Plus (Global)" case "iPhone10,6": return "iPhone X (Global)" // iPod case "iPod1,1": return "iPod Touch 1G" case "iPod2,1": return "iPod Touch 2G" case "iPod3,1": return "iPod Touch 3G" case "iPod4,1": return "iPod Touch 4G" case "iPod5,1": return "iPod Touch 5G" case "iPod7,1": return "iPod Touch 6G" // iPad case "iPad1,1": return "iPad 1" case "iPad2,1": return "iPad 2 (WiFi)" case "iPad2,2": return "iPad 2 (GSM)" case "iPad2,3": return "iPad 2 (CDMA)" case "iPad2,4": return "iPad 2 (WiFi)" case "iPad2,5": return "iPad Mini 1 (WiFi)" case "iPad2,6": return "iPad Mini 1 (GSM)" case "iPad2,7": return "iPad Mini 1 (GSM+CDMA)" case "iPad3,1": return "iPad 3 (WiFi)" case "iPad3,2": return "iPad 3 (GSM+CDMA)" case "iPad3,3": return "iPad 3 (GSM)" case "iPad3,4": return "iPad 4 (WiFi)" case "iPad3,5": return "iPad 4 (GSM)" case "iPad3,6": return "iPad 4 (GSM+CDMA)" case "iPad4,1": return "iPad Air 1 (WiFi)" case "iPad4,2": return "iPad Air 1 (Cellular)" case "iPad4,3": return "iPad Air" case "iPad4,4": return "iPad Mini 2 (WiFi)" case "iPad4,5": return "iPad Mini 2 (Cellular)" case "iPad4,6": return "iPad Mini 2 (Rev)" case "iPad4,7": return "iPad Mini 3 (WiFi)" case "iPad4,8": return "iPad Mini 3 (A1600)" case "iPad4,9": return "iPad Mini 3 (A1601)" case "iPad5,1": return "iPad Mini 4 (WiFi)" case "iPad5,2": return "iPad Mini 4 (Cellular)" case "iPad5,3": return "iPad Air 2 (WiFi)" case "iPad5,4": return "iPad Air 2 (Cellular)" case "iPad6,3": return "iPad Pro 9.7 (WiFi)" case "iPad6,4": return "iPad Pro 9.7 (Cellular)" case "iPad6,7": return "iPad Pro 12.9 (WiFi)" case "iPad6,8": return "iPad Pro 12.9 (Cellular)" // Apple Watch case "Watch1,1": return "Apple Watch 38mm" case "Watch1,2": return "Apple Watch 42mm" case "Watch2,3": return "Apple Watch 38mm (Series 2)" case "Watch2,4": return "Apple Watch 42mm (Series 2)" case "Watch2,6": return "Apple Watch 38mm (Series 1)" case "Watch2,7": return "Apple Watch 42mm (Series 1)" // Apple TV case "AppleTV2,1": return "Apple TV 2G" case "AppleTV3,1": return "Apple TV 3G" case "AppleTV3,2": return "Apple TV 3G (2013)" case "AppleTV5,3": return "Apple TV 4G" case "i386": return "Simulator" case "x86_64": return "Simulator" default: return nil } } } #if os(OSX) import AppKit extension Device { /// Returns the version number of the current OS as String i.e. "1.2" or "9.4" internal static func osVersionForCurrentDevice() -> String { let version = ProcessInfo.processInfo.operatingSystemVersion return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" } // Returns the screen size in points internal static func screenSizeForCurrentDevice() -> CGSize { guard let mainScreen = NSScreen.main else { return CGSize.zero } return mainScreen.visibleFrame.size } // Returns the screen size in pixels internal static func nativeScreenSizeForCurrentDevice() -> CGSize? { return nil } } #elseif os(iOS) || os(tvOS) import UIKit extension Device { /// Returns the version number of the current OS as String i.e. "1.2" or "9.4" internal static func osVersionForCurrentDevice() -> String { return UIDevice.current.systemVersion } // Returns the screen size in points internal static func screenSizeForCurrentDevice() -> CGSize { let bounds = UIScreen.main.bounds return bounds.size } // Returns the screen size in pixels internal static func nativeScreenSizeForCurrentDevice() -> CGSize { let bounds = UIScreen.main.nativeBounds return bounds.size } } #endif