diff --git a/CHANGELOG.md b/CHANGELOG.md index 09804786..f96c3c75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +### New October 2026 devices + +This version adds support for iPad mini (A20 Pro) and Apple TV 4K (4th generation), including hardware identifiers, display metrics and technical specification links: ([#520](https://github.com/devicekit/DeviceKit/pull/520)) + +| Device | Case value | +| --- | --- | +| iPad mini (A20 Pro) | `Device.iPadMiniA20Pro` | +| Apple TV 4K (4th generation) | `Device.appleTV4K4` | + ## Version 5.10.0 Releasedate: 2026-11-01 @@ -27,7 +36,6 @@ Display metrics describe the outer display: 5.4 inches, a 233:339 aspect ratio ( ### Bug fixes - Fix `isSimulator` returning `false` for simulators of unknown devices. ([#507](https://github.com/devicekit/DeviceKit/pull/507)) - ## Version 5.9.0 Releasedate: 2026-09-22 diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index b10138c7..e473855a 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -346,6 +346,8 @@ public enum Device { /// /// ![Image](https://cdsassets.apple.com/live/7WUAS350/images/tech-specs/iPad_mini_A17_Pro_Wi-Fi_Lineup_Print__USEN.png) case iPadMiniA17Pro + /// Device is an [iPad mini (A20 Pro)](https://www.apple.com/ipad-mini/specs/) + case iPadMiniA20Pro /// Device is an [iPad Pro 9.7-inch](https://support.apple.com/kb/SP739) /// /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP739/SP739.png) @@ -431,6 +433,8 @@ public enum Device { /// /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP886/apple-tv-4k-3gen_2x.png) case appleTV4K3 + /// Device is an [Apple TV 4K (4th generation)](https://www.apple.com/apple-tv-4k/specs/) + case appleTV4K4 #elseif os(watchOS) /// Device is an [Apple Watch (1st generation)](https://support.apple.com/kb/SP735) /// @@ -671,6 +675,7 @@ public enum Device { case "iPad11,1", "iPad11,2": return iPadMini5 case "iPad14,1", "iPad14,2": return iPadMini6 case "iPad16,1", "iPad16,2": return iPadMiniA17Pro + case "iPad19,1", "iPad19,2": return iPadMiniA20Pro case "iPad6,3", "iPad6,4": return iPadPro9Inch case "iPad6,7", "iPad6,8": return iPadPro12Inch case "iPad7,1", "iPad7,2": return iPadPro12Inch2 @@ -697,6 +702,7 @@ public enum Device { case "AppleTV6,2": return appleTV4K case "AppleTV11,1": return appleTV4K2 case "AppleTV14,1": return appleTV4K3 + case "AppleTV18,1": return appleTV4K4 case "i386", "x86_64", "arm64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS")) default: return unknown(identifier) } @@ -865,6 +871,7 @@ public enum Device { case .iPadMini5: return 7.9 case .iPadMini6: return 8.3 case .iPadMiniA17Pro: return 8.3 + case .iPadMiniA20Pro: return 8.5 case .iPadPro9Inch: return 9.7 case .iPadPro12Inch: return 12.9 case .iPadPro12Inch2: return 12.9 @@ -1017,6 +1024,7 @@ public enum Device { case .iPadMini5: return (width: 3, height: 4) case .iPadMini6: return (width: 744, height: 1133) case .iPadMiniA17Pro: return (width: 744, height: 1133) + case .iPadMiniA20Pro: return (width: 756, height: 1158) case .iPadPro9Inch: return (width: 3, height: 4) case .iPadPro12Inch: return (width: 3, height: 4) case .iPadPro12Inch2: return (width: 3, height: 4) @@ -1098,7 +1106,7 @@ public enum Device { /// All iPads public static var allPads: [Device] { - return [.iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// All X-Series Devices @@ -1119,7 +1127,7 @@ public enum Device { /// All mini Devices public static var allMiniDevices: [Device] { - return [.iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro] + return [.iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro] } /// All simulator iPods @@ -1195,7 +1203,7 @@ public enum Device { /// All Touch ID Capable Devices public static var allTouchIDCapableDevices: [Device] { - return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneSE2, .iPhoneSE3, .iPhoneDuo, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch] + return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneSE2, .iPhoneSE3, .iPhoneDuo, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch] } /// All Face ID Capable Devices @@ -1205,7 +1213,7 @@ public enum Device { /// All Devices with Touch ID or Face ID public static var allBiometricAuthenticationCapableDevices: [Device] { - return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns whether or not the device has Touch ID @@ -1240,7 +1248,7 @@ public enum Device { /// All devices that feature a screen with rounded corners. public static var allDevicesWithRoundedDisplayCorners: [Device] { - return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns whether or not the device has a screen with rounded corners. @@ -1280,7 +1288,7 @@ public enum Device { /// All devices that support 5G. public static var allDevicesWith5gSupport: [Device] { - return [.iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns whether or not the device has 5G support. @@ -1295,7 +1303,7 @@ public enum Device { /// model capabilities and does not guarantee eSIM availability on a particular device. /// See https://support.apple.com/en-us/109317 and https://support.apple.com/en-us/119592. public static var allDevicesWithEsimSupport: [Device] { - return [.iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns whether the device model supports eSIM. Simulators use their simulated model. @@ -1329,7 +1337,7 @@ public enum Device { /// All devices that have a USB-C connectivity. public static var allDevicesWithUSBCConnectivity: [Device] { - return [.iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns whether or not the device has a USB-C power supply. @@ -1339,7 +1347,7 @@ public enum Device { #elseif os(tvOS) /// All TVs public static var allTVs: [Device] { - return [.appleTVHD, .appleTV4K, .appleTV4K2, .appleTV4K3] + return [.appleTVHD, .appleTV4K, .appleTV4K2, .appleTV4K3, .appleTV4K4] } /// All simulator TVs @@ -1603,6 +1611,7 @@ public enum Device { case .iPadMini5: return 326 case .iPadMini6: return 326 case .iPadMiniA17Pro: return 326 + case .iPadMiniA20Pro: return 326 case .iPadPro9Inch: return 264 case .iPadPro12Inch: return 264 case .iPadPro12Inch2: return 264 @@ -1787,6 +1796,7 @@ extension Device: CustomStringConvertible { case .iPadMini5: return "iPad mini (5th generation)" case .iPadMini6: return "iPad mini (6th generation)" case .iPadMiniA17Pro: return "iPad mini (A17 Pro)" + case .iPadMiniA20Pro: return "iPad mini (A20 Pro)" case .iPadPro9Inch: return "iPad Pro (9.7-inch)" case .iPadPro12Inch: return "iPad Pro (12.9-inch)" case .iPadPro12Inch2: return "iPad Pro (12.9-inch) (2nd generation)" @@ -1854,6 +1864,7 @@ extension Device: CustomStringConvertible { case .appleTV4K: return "Apple TV 4K" case .appleTV4K2: return "Apple TV 4K (2nd generation)" case .appleTV4K3: return "Apple TV 4K (3rd generation)" + case .appleTV4K4: return "Apple TV 4K (4th generation)" case .simulator(let model): return "Simulator (\(model.description))" case .unknown(let identifier): return identifier } @@ -1958,6 +1969,7 @@ extension Device: CustomStringConvertible { case .iPadMini5: return "iPad mini (5th generation)" case .iPadMini6: return "iPad mini (6th generation)" case .iPadMiniA17Pro: return "iPad mini (A17 Pro)" + case .iPadMiniA20Pro: return "iPad mini (A20 Pro)" case .iPadPro9Inch: return "iPad Pro (9.7-inch)" case .iPadPro12Inch: return "iPad Pro (12.9-inch)" case .iPadPro12Inch2: return "iPad Pro (12.9-inch) (2nd generation)" @@ -2025,6 +2037,7 @@ extension Device: CustomStringConvertible { case .appleTV4K: return "Apple TV 4K" case .appleTV4K2: return "Apple TV 4K (2nd generation)" case .appleTV4K3: return "Apple TV 4K (3rd generation)" + case .appleTV4K4: return "Apple TV 4K (4th generation)" case .simulator(let model): return "Simulator (\(model.safeDescription))" case .unknown(let identifier): return identifier } @@ -2296,7 +2309,7 @@ extension Device { /// All Apple Pencil Capable Devices public static var allApplePencilCapableDevices: [Device] { - return [.iPhoneDuo, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPhoneDuo, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// Returns supported version of the Apple Pencil @@ -2335,6 +2348,7 @@ extension Device { case .iPadAir11M4: return [.firstGenerationUsbC, .pro] case .iPadAir13M4: return [.firstGenerationUsbC, .pro] case .iPadMiniA17Pro: return [.firstGenerationUsbC, .pro] + case .iPadMiniA20Pro: return [.firstGenerationUsbC, .pro] case .iPadPro11M4: return [.firstGenerationUsbC, .pro] case .iPadPro13M4: return [.firstGenerationUsbC, .pro] case .simulator(let model): return model.applePencilSupport @@ -2409,6 +2423,7 @@ extension Device { case .iPadMini5: return [.wide] case .iPadMini6: return [.wide] case .iPadMiniA17Pro: return [.wide] + case .iPadMiniA20Pro: return [.wide] case .iPadPro9Inch: return [.wide] case .iPadPro12Inch: return [.wide] case .iPadPro12Inch2: return [.wide] @@ -2465,7 +2480,7 @@ extension Device { /// All devices that feature a camera public static var allDevicesWithCamera: [Device] { - return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// All devices that feature a normal camera @@ -2476,7 +2491,7 @@ extension Device { /// All devices that feature a wide camera public static var allDevicesWithWideCamera: [Device] { - return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] + return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPhone13, .iPhone13Mini, .iPhone13Pro, .iPhone13ProMax, .iPhoneSE3, .iPhone14, .iPhone14Plus, .iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, .iPhone16e, .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e, .iPhone18Pro, .iPhone18ProMax, .iPhoneDuo, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPad9, .iPad10, .iPadA16, .iPadAir4, .iPadAir5, .iPadAir11M2, .iPadAir13M2, .iPadAir11M3, .iPadAir13M3, .iPadAir11M4, .iPadAir13M4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadMini6, .iPadMiniA17Pro, .iPadMiniA20Pro, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, .iPadPro12Inch6, .iPadPro11M4, .iPadPro13M4, .iPadPro11M5, .iPadPro13M5] } /// All devices that feature a telephoto camera @@ -2691,6 +2706,7 @@ extension Device { case .iPadMini5: return .a12Bionic case .iPadMini6: return .a15Bionic case .iPadMiniA17Pro: return .a17Pro + case .iPadMiniA20Pro: return .a20Pro case .iPadPro9Inch: return .a9X case .iPadPro12Inch: return .a9X case .iPadPro12Inch2: return .a10XFusion @@ -2758,6 +2774,7 @@ extension Device { case .appleTV4K: return .a10XFusion case .appleTV4K2: return .a12Bionic case .appleTV4K3: return .a15Bionic + case .appleTV4K4: return .a19 case .simulator(let model): return model.cpu case .unknown: return .unknown } diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index af7f2821..fa54e830 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -382,6 +382,12 @@ iPads = [ cpu="a17Pro", isPadMiniFormFactor=True, hasTouchID=True, hasRoundedDisplayCorners=True, applePencilSupport=34, cameras=1, hasUSBCConnectivity=True, has5gSupport=True, hasEsimSupport=True), + # Specs: https://www.apple.com/ipad-mini/specs/ (verified 2026-10-27). + # Identifiers: https://theapplewiki.com/wiki/Firmware/iPad_mini/27.x (verified 2026-10-27). + Device("iPadMiniA20Pro", "Device is an [iPad mini (A20 Pro)](https://www.apple.com/ipad-mini/specs/)", "", ["iPad19,1", "iPad19,2"], 8.5, (756, 1158), "iPad mini (A20 Pro)", "iPad mini (A20 Pro)", 326, + cpu="a20Pro", isPadMiniFormFactor=True, hasTouchID=True, hasRoundedDisplayCorners=True, + applePencilSupport=34, cameras=1, hasUSBCConnectivity=True, has5gSupport=True, + hasEsimSupport=True), Device("iPadPro9Inch", "Device is an [iPad Pro 9.7-inch](https://support.apple.com/kb/SP739)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP739/SP739.png", ["iPad6,3", "iPad6,4"], 9.7, (3, 4), "iPad Pro (9.7-inch)", "iPad Pro (9.7-inch)", 264, cpu="a9X", isPro=True, hasTouchID=True, applePencilSupport=1, cameras=1), Device("iPadPro12Inch", "Device is an [iPad Pro 12-inch](https://support.apple.com/kb/SP723)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP723/SP723-iPad_Pro_2x.png", ["iPad6,7", "iPad6,8"], 12.9, (3, 4), "iPad Pro (12.9-inch)", "iPad Pro (12.9-inch)", 264, @@ -454,6 +460,10 @@ tvs = [ cpu="a12Bionic"), Device("appleTV4K3", "Device is an [Apple TV 4K (3rd generation)](https://support.apple.com/kb/SP886)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP886/apple-tv-4k-3gen_2x.png", ["AppleTV14,1"], 0, (), "Apple TV 4K (3rd generation)", "Apple TV 4K (3rd generation)", -1, cpu="a15Bionic"), + # Specs: https://www.apple.com/apple-tv-4k/specs/ (verified 2026-10-27). + # Identifiers: https://theapplewiki.com/wiki/Apple_TV_4K_(4th_generation) (verified 2026-10-27). + Device("appleTV4K4", "Device is an [Apple TV 4K (4th generation)](https://www.apple.com/apple-tv-4k/specs/)", "", ["AppleTV18,1"], 0, (), "Apple TV 4K (4th generation)", "Apple TV 4K (4th generation)", -1, + cpu="a19"), ] # watchOS diff --git a/Tests/Tests.swift b/Tests/Tests.swift index 2809633a..ac21f75b 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -134,6 +134,47 @@ class DeviceKitTests: XCTestCase { } #endif + #if os(iOS) || os(tvOS) + func testOctober2026Devices() { + #if os(iOS) + let model = Device.iPadMiniA20Pro + for identifier in ["iPad19,1", "iPad19,2"] { + XCTAssertEqual(Device.mapToDevice(identifier: identifier), model, identifier) + } + XCTAssertTrue(model.isPad) + XCTAssertTrue(Device.allRealDevices.contains(model)) + XCTAssertTrue(Device.allSimulators.contains(.simulator(model))) + XCTAssertTrue(Device.allMiniDevices.contains(model)) + XCTAssertEqual(model.cameras, [.wide]) + for variant in [model, .simulator(model)] { + XCTAssertEqual(variant.description, variant == model ? "iPad mini (A20 Pro)" : "Simulator (iPad mini (A20 Pro))") + XCTAssertEqual(variant.cpu, .a20Pro) + XCTAssertEqual(variant.diagonal, 8.5) + XCTAssertEqual(variant.screenRatio.width, 756) + XCTAssertEqual(variant.screenRatio.height, 1158) + XCTAssertEqual(variant.ppi, 326) + XCTAssertTrue(variant.isTouchIDCapable) + XCTAssertFalse(variant.isFaceIDCapable) + XCTAssertEqual(variant.applePencilSupport, [.firstGenerationUsbC, .pro]) + XCTAssertTrue(variant.hasEsimSupport) + XCTAssertFalse(variant.hasDualEsimSupport) + } + #else + let model = Device.appleTV4K4 + XCTAssertEqual(Device.mapToDevice(identifier: "AppleTV18,1"), model) + XCTAssertTrue(Device.allRealDevices.contains(model)) + XCTAssertTrue(Device.allSimulators.contains(.simulator(model))) + XCTAssertEqual(model.description, "Apple TV 4K (4th generation)") + XCTAssertEqual(model.cpu, .a19) + XCTAssertEqual(model.ppi, nil) + #endif + // Unannounced identifiers must remain unknown. + for identifier in ["iPad19,3", "iPad19,4", "AppleTV18,2", ""] { + XCTAssertEqual(Device.mapToDevice(identifier: identifier), .unknown(identifier)) + } + } + #endif + func testDeviceSimulator() { #if os(macOS) XCTAssertFalse(device.isOneOf(Device.allSimulators)) @@ -232,6 +273,7 @@ class DeviceKitTests: XCTestCase { XCTAssertEqual(Device.iPadMini5.cpu, Device.CPU.a12Bionic) XCTAssertEqual(Device.iPadMini6.cpu, Device.CPU.a15Bionic) XCTAssertEqual(Device.iPadMiniA17Pro.cpu, Device.CPU.a17Pro) + XCTAssertEqual(Device.iPadMiniA20Pro.cpu, Device.CPU.a20Pro) XCTAssertEqual(Device.iPadPro11Inch.cpu, Device.CPU.a12XBionic) XCTAssertEqual(Device.iPadPro11Inch2.cpu, Device.CPU.a12ZBionic) XCTAssertEqual(Device.iPadPro11Inch3.cpu, Device.CPU.m1) @@ -248,6 +290,7 @@ class DeviceKitTests: XCTestCase { XCTAssertEqual(Device.appleTV4K.cpu, Device.CPU.a10XFusion) XCTAssertEqual(Device.appleTV4K2.cpu, Device.CPU.a12Bionic) XCTAssertEqual(Device.appleTV4K3.cpu, Device.CPU.a15Bionic) + XCTAssertEqual(Device.appleTV4K4.cpu, Device.CPU.a19) #endif } @@ -748,6 +791,7 @@ class DeviceKitTests: XCTestCase { .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, + .iPadMiniA20Pro, .iPadPro11Inch3, .iPadPro12Inch5, .iPadPro11Inch4, @@ -784,7 +828,8 @@ class DeviceKitTests: XCTestCase { .iPhone17, .iPhone17Pro, .iPhone17ProMax, .iPhoneAir, .iPhone17e] let pads: [Device] = [.iPadAir11M2, .iPadAir13M2, .iPadPro11M4, .iPadPro13M4, .iPadMiniA17Pro, .iPadA16, .iPadAir11M3, .iPadAir13M3, - .iPadPro11M5, .iPadPro13M5, .iPadAir11M4, .iPadAir13M4] + .iPadPro11M5, .iPadPro13M5, .iPadAir11M4, .iPadAir13M4, + .iPadMiniA20Pro] for model in phones + pads { for variant in [model, .simulator(model)] { XCTAssertTrue(variant.hasEsimSupport, "\(variant)") @@ -928,6 +973,7 @@ class DeviceKitTests: XCTestCase { .iPadAir13M4, .iPadMini6, .iPadMiniA17Pro, + .iPadMiniA20Pro, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2,