Как определить модель текущего iPhone или устройства iOS в Swift?
Решение: получаем точную модель устройства через sysctl
Стандартный UIDevice.current.model действительно возвращает только общий тип. Чтобы получить точный идентификатор модели (например, "iPhone15,3" для iPhone 15 Pro Max), нужно использовать системный вызов sysctl. Этот метод работает на всех реальных устройствах и не требует дополнительных зависимостей.
Шаг 1: Получаем идентификатор модели
Создайте расширение для UIDevice:
import UIKit
extension UIDevice {
var modelIdentifier: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.compactMap { element -> String? in
guard let value = element.value as? Int8, value != 0 else { return nil }
return String(UnicodeScalar(UInt8(value)))
}.joined()
return identifier
}
var modelName: String {
let identifier = modelIdentifier
return UIDevice.modelName(for: identifier)
}
static func modelName(for identifier: String) -> String {
let modelMap: [String: String] = [
"iPhone1,1": "iPhone 2G",
"iPhone1,2": "iPhone 3G",
"iPhone2,1": "iPhone 3GS",
"iPhone3,1": "iPhone 4 (GSM)",
"iPhone3,3": "iPhone 4 (CDMA)",
"iPhone4,1": "iPhone 4S",
"iPhone5,1": "iPhone 5 (GSM)",
"iPhone5,2": "iPhone 5 (CDMA)",
"iPhone5,3": "iPhone 5c",
"iPhone5,4": "iPhone 5c",
"iPhone6,1": "iPhone 5s",
"iPhone6,2": "iPhone 5s",
"iPhone7,2": "iPhone 6",
"iPhone7,1": "iPhone 6 Plus",
"iPhone8,1": "iPhone 6s",
"iPhone8,2": "iPhone 6s Plus",
"iPhone8,4": "iPhone SE (1st gen)",
"iPhone9,1": "iPhone 7",
"iPhone9,3": "iPhone 7",
"iPhone9,2": "iPhone 7 Plus",
"iPhone9,4": "iPhone 7 Plus",
"iPhone10,1": "iPhone 8",
"iPhone10,4": "iPhone 8",
"iPhone10,2": "iPhone 8 Plus",
"iPhone10,5": "iPhone 8 Plus",
"iPhone10,3": "iPhone X",
"iPhone10,6": "iPhone X",
"iPhone11,2": "iPhone XS",
"iPhone11,4": "iPhone XS Max",
"iPhone11,6": "iPhone XS Max",
"iPhone11,8": "iPhone XR",
"iPhone12,1": "iPhone 11",
"iPhone12,3": "iPhone 11 Pro",
"iPhone12,5": "iPhone 11 Pro Max",
"iPhone12,8": "iPhone SE (2nd gen)",
"iPhone13,1": "iPhone 12 mini",
"iPhone13,2": "iPhone 12",
"iPhone13,3": "iPhone 12 Pro",
"iPhone13,4": "iPhone 12 Pro Max",
"iPhone14,2": "iPhone 13 Pro",
"iPhone14,3": "iPhone 13 Pro Max",
"iPhone14,4": "iPhone 13 mini",
"iPhone14,5": "iPhone 13",
"iPhone14,6": "iPhone SE (3rd gen)",
"iPhone14,7": "iPhone 14",
"iPhone14,8": "iPhone 14 Plus",
"iPhone15,1": "iPhone 14 Pro",
"iPhone15,2": "iPhone 14 Pro Max",
"iPhone15,3": "iPhone 15 Pro Max",
"iPhone15,4": "iPhone 15 Pro",
"iPhone15,5": "iPhone 15",
"iPhone16,1": "iPhone 16 Pro",
"iPhone16,2": "iPhone 16 Pro Max",
"iPhone16,3": "iPhone 16",
// iPad и iPod можно добавить по аналогии
]
return modelMap[identifier] ?? identifier
}
}
Шаг 2: Использование
Теперь вы можете получить информацию так:
let device = UIDevice.current
print("Идентификатор: \(device.modelIdentifier)") // iPhone15,3
print("Название модели: \(device.modelName)") // iPhone 15 Pro Max
Обработка симулятора
На симуляторе sysctl вернёт "x86_64" (Intel) или "arm64" (Apple Silicon). Чтобы получить модель, которую симулятор эмулирует, используйте:
extension UIDevice {
var isSimulator: Bool {
return modelIdentifier == "x86_64" || modelIdentifier == "arm64"
}
var simulatorModelIdentifier: String? {
return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"]
}
}
Важные замечания
- Обновляйте словарь modelMap — Apple регулярно выпускает новые устройства, и их идентификаторы нужно добавлять вручную. Следите за обновлениями на theiphonewiki.com.
- Для iPad и iPod — расширьте словарь аналогично, используя префиксы "iPad" и "iPod".
- Не используйте для критической логики — определение модели может сломаться при появлении нового устройства. Для адаптации UI лучше используйте
UITraitCollectionилиUIScreen. - Конфиденциальность — не отправляйте идентификатор модели на сервер без явного согласия пользователя.
Альтернатива: фреймворк DeviceKit
Если не хотите поддерживать словарь вручную, используйте CocoaPod/SPM пакет DeviceKit. Он автоматически обновляется и предоставляет удобный API:
import DeviceKit
let device = Device.current
print(device.description) // "iPhone 15 Pro Max"
print(device.isOneOf([.iPhone14Pro, .iPhone15ProMax])) // Проверка конкретных моделей
<<Альтернативный подход: использование Bundle.main.infoDictionary
Если вам нужно только узнать, является ли устройство iPhone, iPad или iPod, и не требуется точная модель, можно обойтись без sysctl. Но для точной модели есть ещё один способ — читать файл /System/Library/CoreServices/SystemVersion.plist или использовать uname() через C-функции напрямую.
Простой метод для iOS 16+
Начиная с iOS 16, Apple добавила свойство modelName в UIDevice, но оно всё ещё возвращает обобщённые названия. Однако для определения конкретной модели можно использовать sysctlbyname с аргументом "hw.machine":
import Foundation
func getHardwareModel() -> String {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
return String(cString: machine)
}
let model = getHardwareModel()
print(model) // "iPhone15,3"
Обработка ошибок
Этот код не обрабатывает возможные ошибки sysctl. Для продакшена лучше добавить проверку:
func getHardwareModelSafe() -> String? {
var size = 0
guard sysctlbyname("hw.machine", nil, &size, nil, 0) == 0, size > 0 else { return nil }
var machine = [CChar](repeating: 0, count: size)
guard sysctlbyname("hw.machine", &machine, &size, nil, 0) == 0 else { return nil }
return String(cString: machine)
}
Когда это полезно
Ответов пока нет.
Войдите чтобы оставить ответ