Определить, является ли устройство iPhone X


263

Мое приложение для iOS использует настраиваемую высоту, UINavigationBarчто приводит к некоторым проблемам на новом iPhone X.

Кто-нибудь уже знает, как надежно определять программно (в Objective-C), если приложение работает на iPhone X?

РЕДАКТИРОВАТЬ:

Конечно, проверка размера экрана возможна, однако мне интересно, есть ли какой-нибудь метод «встроенного» типа, как TARGET_OS_IPHONEобнаружение iOS ...

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    if (screenSize.height == 812)
        NSLog(@"iPhone X");
}

РЕДАКТИРОВАТЬ 2:

Я не думаю, что мой вопрос является дубликатом связанного вопроса. Конечно, существуют методы для «измерения» различных свойств текущего устройства и использования результатов для определения того, какое устройство используется. Тем не менее, это был не фактический вопрос моего вопроса, который я попытался подчеркнуть в своем первом редактировании.

Фактический вопрос: «Можно ли напрямую определить, является ли текущее устройство iPhone X (например, с помощью некоторой функции SDK), или мне нужно использовать косвенные измерения» ?

Исходя из приведенных ответов, я предполагаю, что ответ «Нет, прямых методов нет. Измерения - это путь».


iPhone X имеет разрешение экрана, отличное от других.
Эль Томат

2
Да, как я уже упоминал в моем редактировании, можно проверить размер экрана. Однако вопрос в том, существует ли «прямой» метод для запроса типа устройства, а не «косвенные» измерения ...
Андрей Херфорд

3
Автор просто хочет получить тип устройства, а не разрешение экрана. Почему бы не проверить имя машины напрямую? @lubilis прав.
Итачи

2
почему бы вам просто не использовать руководства по безопасным зонам, как это рекомендует Apple?
Holex

4
ВАЖНО, будущие разработчики: не определяйте это, используя высоту экрана, как предлагают современные топовые решения, это плохо, поскольку это может привести к ложным срабатываниям для будущих устройств; не будет работать, если UIWindow еще не визуализировалось (как в ваших функциях инициализации AppDelegate), не будет работать в ландшафтных приложениях и может не работать на симуляторе, если установлен масштаб. НИКОГДА не используйте магические числа для подобных вещей! Вы можете проверить аппаратные флаги, чтобы гарантировать успех, как я сделал здесь: stackoverflow.com/a/51511947/2057171
Альберт Реншоу

Ответы:


385

На основании вашего вопроса ответ - нет. Прямых методов нет. Для получения дополнительной информации вы можете получить информацию здесь:

и

Высота iPhone X составляет 2436 пикселей

От устройств Размеры экрана и разрешение :

введите описание изображения здесь

Из размеров и ориентации экрана устройства :

введите описание изображения здесь

Свифт 3 и позже :

if UIDevice().userInterfaceIdiom == .phone {
    switch UIScreen.main.nativeBounds.height {
        case 1136:
            print("iPhone 5 or 5S or 5C")

        case 1334:
            print("iPhone 6/6S/7/8")

        case 1920, 2208:
            print("iPhone 6+/6S+/7+/8+")

        case 2436:
            print("iPhone X/XS/11 Pro")

        case 2688:
            print("iPhone XS Max/11 Pro Max")

        case 1792:
            print("iPhone XR/ 11 ")

        default:
            print("Unknown")
        }
    }

Цель-C :

if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
    switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) {
        case 1136:
            printf("iPhone 5 or 5S or 5C");
                break;

        case 1334:
            printf("iPhone 6/6S/7/8");
            break;

        case 1920, 2208:
            printf("iPhone 6+/6S+/7+/8+");
            break;

       case 2436:
            print("iPhone X/XS/11 Pro");
             break;

        case 2688:
            print("iPhone XS Max/11 Pro Max");
             break;

        case 1792:
            print("iPhone XR/ 11 ");
             break;

        default:
            printf("Unknown");
            break;
    }
}

Xamarin.iOS :

if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) {
    if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1136) {
        Console.WriteLine("iPhone 5 or 5S or 5C");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1334) {
        Console.WriteLine("iPhone 6/6S/7/8");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1920 || (UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2208) {
        Console.WriteLine("iPhone 6+/6S+/7+/8+");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2436) {
        Console.WriteLine("iPhone X, XS, 11 Pro");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
        Console.WriteLine("iPhone XS Max, 11 Pro Max");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
        Console.WriteLine("iPhone XR, 11");
    } else {
        Console.WriteLine("Unknown");
    }
}

На основании вашего вопроса следующим образом:

Или используйте screenSize.heightкак float, а 812.0f не int 812.

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
        // 812.0 on iPhone X, XS
        // 896.0 on iPhone XS Max, XR.

    if (screenSize.height >= 812.0f)
        NSLog(@"iPhone X");
    }

Для получения дополнительной информации вы можете обратиться к следующей странице в Руководстве по интерфейсу пользователя iOS:

Свифт :

Определить с помощью topNotch:

Если кто-то рассматривает возможность использования метки для обнаружения iPhoneX, имейте в виду, что на «ландшафте» он одинаков для всех iPhone.

var hasTopNotch: Bool {
    if #available(iOS 13.0,  *) {
        return UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.safeAreaInsets.top ?? 0 > 20
    }else{
     return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
    }

    return false
}

Цель-C :

- (BOOL)hasTopNotch {
   if (@available(iOS 13.0, *)) {
       return [self keyWindow].safeAreaInsets.top > 20.0;
   }else{
       return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
   }
   return  NO;
}

- (UIWindow*)keyWindow {
    UIWindow        *foundWindow = nil;
    NSArray         *windows = [[UIApplication sharedApplication]windows];
    for (UIWindow   *window in windows) {
        if (window.isKeyWindow) {
            foundWindow = window;
            break;
        }
    }
    return foundWindow;
}

ОБНОВЛЕНИЕ :

Не используйте userInterfaceIdiomсвойство для определения типа устройства, как объясняется в документации для userInterfaceIdiom :

Для универсальных приложений вы можете использовать это свойство, чтобы адаптировать поведение вашего приложения для конкретного типа устройства. Например, устройства iPhone и iPad имеют разные размеры экрана, поэтому вам может потребоваться создать разные представления и элементы управления в зависимости от типа текущего устройства.

То есть это свойство просто используется для определения стиля представления запущенного приложения. Тем не менее, приложение iPhone (не универсальное) может быть установлено на устройстве iPad через App Store, в этом случае userInterfaceIdiomбудет возвращеноUIUserInterfaceIdiomPhone .

Правильный путь - получить имя машины через uname. Проверьте следующее для деталей:


Разрешение iPhone X является 2436 х 1125 пикселей в соответствии с: iphonesoft.fr/2017/09/12/...
Медхи

1
@Medhi - разрешение iphone X составляет - 1125 x 2436 пикселей (плотность пикселей ~ 458 ppi)
Anbu.Karthik

14
НЕТ! Приложение iPhone (не вселенная) может быть установлено на устройстве iPad через App Store, в этом случае такжеuserInterfaceIdiomбудет возвращено приложениеUIUserInterfaceIdiomPhone. Этот ответ неверен.
Итачи

1
@ThreeCoins, пожалуйста, обновите свой ответ для плюсовых устройств согласно предложению Лео Дабуса. Работает на симуляторе Плюс, но не на устройстве.
Хирен Гуджарати

2
Это плохо, поскольку это может привести к ложным срабатываниям для будущих устройств; не будет работать, если UIWindow еще не визуализировал (AppDelegate), не будет работать в ландшафтных приложениях и может не работать на симуляторе, если установлен масштаб. Вы можете проверить аппаратные флаги, чтобы гарантировать успех, как я сделал здесь: stackoverflow.com/a/51511947/2057171
Альберт Реншоу

102

Еще одна возможность, которая работает на iOS 11 и iOS 12, потому что iPhone X является единственным с надписью вверху и вставкой 44. Вот что я действительно обнаруживаю здесь:

Objective-C:

    BOOL iPhoneX = NO;
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
        if (mainWindow.safeAreaInsets.top > 24.0) {
            iPhoneX = YES;
        }
    }

Свифт 4:

/// Has safe area
///
/// with notch: 44.0 on iPhone X, XS, XS Max, XR.
///
/// without notch: 20.0 on iPhone 8 on iOS 12+.
///
static var hasSafeArea: Bool {
    guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 24 else {
        return false
    }
    return true
}

И, конечно, вам может понадобиться проверить левые и правые вставки в безопасных зонах, если вы находитесь в альбомной ориентации.

Редактировать: _window является UIWindow AppDelegate, где эта проверка выполняется в приложении didFinishLaunchingWithOptions.

Обновлен ответ для iOS 12, чтобы проверить, является ли top> 24, а не top> 0.

Редактировать: в симуляторе вы можете перейти к Hardware, Toggle In-Call Status Bar. Это показывает, что высота строки состояния не изменяется на iPhone X на iOS 11 или iPhone XS iOS 12 при вызове. Все, что меняется, это значок времени, который в обоих случаях получает зеленый фон. Вот снимок:

введите описание изображения здесь


5
Вставки безопасной зоны будут содержать высоту строки состояния, если она видна, на других устройствах. Проверка того, равен ли это 0, сообщит только о том, видна ли строка состояния, а не о том, является ли устройство iPhone X.
IMcD23

3
«Это может сломаться в iPhone Xs или iPhone 11 », - сказал Кук.
Итачи

11
Я немного адаптировался и использую, if _window.safeAreaInsets != UIEdgeInsets.zeroчтобы учесть любую ориентацию устройства
Fraser

2
Если вы не хотите использовать .top, safeAreaInsets.bottomбудет 34 на iPhone X и 0 на других устройствах
blwinters

7
Предупреждение: не используйте это, оно ломается на iOS 12. Также не задокументировано, что должен делать UIWindow в этом случае. openradar.appspot.com/42372793
steipete

74

Вы должны выполнить различные обнаружения iPhone X в зависимости от фактической необходимости.

для работы с высшей меткой (статусбар, навигационная панель) и т. д.

class var hasTopNotch: Bool {
    if #available(iOS 11.0, tvOS 11.0, *) {
        // with notch: 44.0 on iPhone X, XS, XS Max, XR.
        // without notch: 24.0 on iPad Pro 12.9" 3rd generation, 20.0 on iPhone 8 on iOS 12+.
        return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 24
    }
    return false
}

для работы с нижним индикатором дома (вкладка) и т. д.

class var hasBottomSafeAreaInsets: Bool {
    if #available(iOS 11.0, tvOS 11.0, *) {
        // with home indicator: 34.0 on iPhone X, XS, XS Max, XR.
        // with home indicator: 20.0 on iPad Pro 12.9" 3rd generation.
        return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
    }
    return false
}

для размера фона, полноэкранных функций и т. д.

class var isIphoneXOrBigger: Bool {
    // 812.0 on iPhone X, XS.
    // 896.0 on iPhone XS Max, XR.
    return UIScreen.main.bounds.height >= 812
}

Примечание: в конечном итоге смешайте его с UIDevice.current.userInterfaceIdiom == .phone
примечанием: этот метод требует наличия раскадровки LaunchScreen или соответствующих LaunchImages

для отношения фона, прокрутки и т. д.

class var isIphoneXOrLonger: Bool {
    // 812.0 / 375.0 on iPhone X, XS.
    // 896.0 / 414.0 on iPhone XS Max, XR.
    return UIScreen.main.bounds.height / UIScreen.main.bounds.width >= 896.0 / 414.0
}

Примечание: этот метод требует наличия раскадровки LaunchScreen или соответствующих LaunchImages

для аналитики, статистики, отслеживания и т. д.

Получите идентификатор машины и сравните его с документированными значениями:

class var isIphoneX: Bool {
    var size = 0
    sysctlbyname("hw.machine", nil, &size, nil, 0)
    var machine = [CChar](repeating: 0, count: size)
    sysctlbyname("hw.machine", &machine, &size, nil, 0)
    let model = String(cString: machine)
    return model == "iPhone10,3" || model == "iPhone10,6"
}

Чтобы включить симулятор в качестве действующего iPhone X в аналитику:

class var isIphoneX: Bool {
    let model: String
    if TARGET_OS_SIMULATOR != 0 {
        model = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
    } else {
        var size = 0
        sysctlbyname("hw.machine", nil, &size, nil, 0)
        var machine = [CChar](repeating: 0, count: size)
        sysctlbyname("hw.machine", &machine, &size, nil, 0)
        model = String(cString: machine)
    }
    return model == "iPhone10,3" || model == "iPhone10,6"
}

Чтобы включить iPhone XS, XS Max и XR, просто найдите модели, начинающиеся с «iPhone11»:

return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")

для поддержки faceID

import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
    if #available(iOS 11.0, *) {
        return LAContext().biometryType == .typeFaceID
    }
    return false
}

Я надеялся, что return LAContext().biometryType == .typeFaceIDэто сработает, даже если пользователь отклонит canEvaluatePolicy, но он не работает для меня, он все равно возвращается.none
Джереми

Ну, @ Джереми, это задокументированное поведение, следствие политики конфиденциальности Apple. Вот почему комментарий выше метода.
Cœur

Ах, я неверно истолковал ваш комментарий. Я думал, что вы имели в виду, что использование canEvaluatePolicy может дать сбой, поэтому используйте следующее. Я нахожу немного странным, что вам разрешено проверять, есть ли на устройстве идентификатор лица, пока пользователь не ответит на переключение, а затем вы даже не сможете больше проверять. Как я должен предоставить полезное сообщение об ошибке, чтобы перейти к настройкам и переключить Face ID?
Джереми

@ Джереми, у меня нет iPhone X, поэтому я не знаю. Возможно, вы могли бы использовать обнаружение модели выше ( model == "iPhone10,3" || model == "iPhone10,6"), и если canUseFaceIDвозвращает false, то это означает, что он был отклонен пользователем.
Cœur

1
@MateoOlaya Ничто в моем ответе не будет отклонено Apple: вы можете использовать все это.
Cœur

43

Вы можете сделать это, чтобы обнаружить iPhone X устройство соответствии с размером.

стриж

if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
   //iPhone X
}

Цель - С

if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436)  {
  //iPhone X     
}

введите описание изображения здесь

Но ,

Это не достаточный способ. Что делать, если Apple анонсировала следующий iPhone с таким же размером iPhone X. Поэтому лучший способ - использовать аппаратную строку для обнаружения устройства.

Для нового устройства Аппаратная строка указана ниже.

iPhone 8 - iPhone10,1 или iPhone 10,4

iPhone 8 Plus - iPhone10,2 или iPhone 10,5

iPhone X - iPhone10,3 или iPhone10,6


2
Вы должны использовать [UIDevice currentDevice]вместо[[UIDevice alloc] init]
С. Мацепура

единственная проблема с аппаратной строкой - это то, что она не работает на симуляторе
унылый

39

Проверьте модель устройства / имя машины , НЕ используйте количество точек / пикселей в вашем коде напрямую, это жесткий код и не имеет смысла для аппаратного обеспечения устройства, модель устройства является единственным уникальным идентификатором для типа устройства, которое соответствует .

#import <sys/utsname.h>

NSString* deviceName()
{
    struct utsname systemInfo;
    uname(&systemInfo);

    return [NSString stringWithCString:systemInfo.machine
                          encoding:NSUTF8StringEncoding];
}

Результат:

@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)

Обратитесь к этому ответу .

Полная реализация кода:

#import <sys/utsname.h>

NSString * GetDeviceModel(void)
{
    static dispatch_once_t onceToken;
    static NSString *strModelID = nil;

    dispatch_once(&onceToken, ^{
#if TARGET_IPHONE_SIMULATOR
        strModelID = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
        struct utsname systemInfo;

        uname(&systemInfo);
        strModelID = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
#endif
    });

    return strModelID;
}

// See the `Hardware strings` in https://en.wikipedia.org/wiki/List_of_iOS_devices
BOOL IsiPhoneX(void)
{
    NSString *strModelID = GetDeviceModel();

    return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"];
}

BOOL IsNotchiPhone(void)
{
    NSArray<NSString *> *notchiModels = @[
        @"iPhone10,3", @"iPhone10,6", // iPhone X
        @"iPhone11,2", @"iPhone11,4", @"iPhone11,6", // iPhone XS (Max)
        @"iPhone11,8", // iPhone XR
        @"iPhone12,1", @"iPhone12,3", @"iPhone12,5", // iPhone 11 (Pro (Max))
    ];

    return [notchiModels containsObject:GetDeviceModel()];
}

1
Отличный ответ, поскольку он обрабатывает симулятор правильно. Пожалуйста, добавьте строку #import в раздел «полный код». Я пропустил это (скопировать / вставить) с первой попытки.
mpoisot

1
это мой предпочтительный метод. Обратитесь к этой вики для полного списка строк модели устройства. Как побочный комментарий, @ "iphone10,3" также можно рассматривать как жесткий код.
YvesLeBorg

1
@ YvesLeBorg Да, это действительно критически важный вопрос. Я думаю, что строка аппаратной модели имеет уникальный идентификатор, чем точки экрана для устройства. Как правило, он используется для статистики данных.
Итачи

26
#define IS_IPHONE        (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 480.0)
#define IS_IPHONE_5      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
#define IS_IPHONE_6      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
#define IS_IPHONE_6PLUS  (IS_IPHONE && [[UIScreen mainScreen] nativeScale] == 3.0f)
#define IS_IPHONE_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_IPHONE_X      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)

определить IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds] .size.height == 812.0)

#define IS_IPHONE_XS      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
#define IS_IPHONE_X_MAX      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 896.0)
#define IS_RETINA        ([[UIScreen mainScreen] scale] >= 2.0) // 3.0 for iPhone X, 2.0 for others

#define IS_IPAD_DEVICE   [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]

Примечание: - будьте осторожны, отлично работает только для портретной ориентации


2
Будьте осторожны, он прекрасно работает только для портретной ориентации
CFIFok

1
Спасибо за это. Работает хорошо. В ландшафтном режиме вам нужно настроить эти цифры. Магическое число iPhoneX в ландшафтном режиме - 375.0
pvella

Есть несколько iPhone Plus / Max / Pro, использующих nativeScaleс 3.0, верно?
Итачи

25

Посмотрев на все ответы, я сделал следующее:

Решение (совместимо с Swift 4.1)

extension UIDevice {
    static var isIphoneX: Bool {
        var modelIdentifier = ""
        if isSimulator {
            modelIdentifier = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
        } else {
            var size = 0
            sysctlbyname("hw.machine", nil, &size, nil, 0)
            var machine = [CChar](repeating: 0, count: size)
            sysctlbyname("hw.machine", &machine, &size, nil, 0)
            modelIdentifier = String(cString: machine)
        }

        return modelIdentifier == "iPhone10,3" || modelIdentifier == "iPhone10,6"
    }

    static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0
    }
}

использование

if UIDevice.isIphoneX {
    // is iPhoneX
} else {
    // is not iPhoneX
}

Заметка

В Pre Swift 4.1 вы можете проверить, работает ли приложение на симуляторе, например:

TARGET_OS_SIMULATOR != 0

Начиная с Swift 4.1 и далее, вы можете проверить, работает ли приложение на симуляторе с использованием условия платформы среды Target :

#if targetEnvironment(simulator)
    return true
#else
    return false
#endif

(старый метод все еще будет работать, но этот новый метод более перспективен)


яблоко будет хорошо с этим?
Сурджит Раджпут

@ commando24 Да, я не вижу причин, по которым они могут отклонить приложение из-за этого кода.
Cloud9999Strife

18

Все эти ответы, основанные на размерах, подвержены некорректному поведению на будущих устройствах. Они будут работать сегодня, но что, если в следующем году появится iPhone того же размера, но с камерой и т. Д. Под стеклом, чтобы не было «надреза»? Если единственный вариант - обновить приложение, тогда это плохое решение для вас и ваших клиентов.

Вы также можете проверить строку модели оборудования, такую ​​как «iPhone10,1», но это проблематично, потому что иногда Apple выпускает разные номера моделей для разных операторов по всему миру.

Правильный подход состоит в том, чтобы перепроектировать верхний макет или решить проблемы, возникающие у вас с настраиваемой высотой панели навигации (на этом я бы остановился). Но если вы решите не делать ни одну из этих вещей, осознайте, что все, что вы делаете, является хаком, чтобы заставить это работать сегодня , и вам нужно будет исправить это в какой-то момент, возможно, несколько раз, чтобы сохранить взломы работает.


1
Правильно. Уточнение предположения, что число X всегда будет от A до единицы, что число X всегда будет A, если только условие Y, когда это будет B, просто копает глубже. Размер основан на безопасном районе, номинированном Apple, а не на втором этапе.
Томми

2
Я буду беспокоиться о следующем iPhone, когда он на самом деле там. Я хочу, чтобы мое приложение работало СЕГОДНЯ.
Вахид Амири

13

SWIFT 4+ Ответ

iPhone X, XR, XS, XSMAX, 11 Pro, 11 Pro Max:

Примечание: нужно реальное устройство для теста

Ссылка

 let deviceType = UIDevice.current.modelName
        switch deviceType {
        case "iPhone10,3", "iPhone10,6":
            print("iPhoneX")
        case "iPhone11,2":
            print("iPhone XS")
        case "iPhone11,4":
            print("iPhone XS Max")
        case "iPhone11,6":
            print("iPhone XS Max China")
        case "iPhone11,8":
            print("iPhone XR")
        case "iPhone12,3":
            print("iPhone 11 Pro")
        case "iPhone12,5":
            print("iPhone 11 Pro Max")
        default:
            break
}

extension UIDevice {
    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        return identifier
    }
}

Для метода 1 вы можете убрать свойство «var window» вне функции и просто константу «let» внутри него (тип UIWindow, т.е. не обязательно). Мне нравится этот ответ, поскольку при запуске self.view.window может иметь значение nil, а UIApplication.shared.keyWindow также может иметь значение nil, тогда как создание UIWindow таким образом работает каждый раз.
Rolleric

11

Многоразовое расширение SWIFT 4/5 с поддержкой iPhone 11

    public extension UIDevice {

    public enum `Type` {
        case iPad
        case iPhone_unknown
        case iPhone_5_5S_5C
        case iPhone_6_6S_7_8
        case iPhone_6_6S_7_8_PLUS
        case iPhone_X_Xs
        case iPhone_Xs_11_Pro_Max
        case iPhone_Xr_11
        case iPhone_11_Pro
    }

    public var hasHomeButton: Bool {
        switch type {
        case .iPhone_X_Xs, .iPhone_Xr_11, .iPhone_Xs_11_Pro_Max, .iPhone_11_Pro:
            return false
        default:
            return true
        }
    }

    public var type: Type {
        if userInterfaceIdiom == .phone {
            switch UIScreen.main.nativeBounds.height {
            case 1136: return .iPhone_5_5S_5C
            case 1334: return .iPhone_6_6S_7_8
            case 1920, 2208: return .iPhone_6_6S_7_8_PLUS
            case 2436: return .iPhone_X_Xs
            case 2688: return .iPhone_Xs_11_Pro_Max
            case 1792: return .iPhone_Xr_11
            case 2426: return .iPhone_11_Pro
            default: return .iPhone_unknown
        }
        }
        return .iPad
   }
}

2
хорошее расширение, но самое полезное здесьUIDevice.current.hasHomeButton
WINSergey

1
@ale_stro Хорошо ли использовать userInterfaceIdiom для определения устройств для универсального приложения? большинство людей не рекомендует это. есть ли вред его использовать?
Шакир сказал

10

Да, это возможно. Загрузите расширение UIDevice-Hardware (или установите через CocoaPod 'UIDevice-Hardware') и затем используйте:

NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];

Обратите внимание, что это не будет работать в симуляторе, только на реальном устройстве.


Весь код устройства здесь: iphonesoft.fr/2016/10/31/... Пример: iPhone X: iPhone10,5 и iPhone10,6
Medhi

В аппаратному строки из википедии сказал «iPhone10,3 и iPhone10,6». @Medhi
Итачи

@Medhi, вы можете использовать ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIF‌​IER"]в симуляторе, чтобы получить реальные значения из XCode.
Cœur

9

Согласно ответу @ saswanb, это версия Swift 4:

var iphoneX = false
if #available(iOS 11.0, *) {
    if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
        iphoneX = true
    }
}

Строка состояния также считается за пределами безопасной зоны! так что это вернет ложные срабатывания! Это должно быть выше, чем 20 очков (высота строки состояния). Возвращается также значение true, если устройством является iPhone Xs, R или Xs Max.
MQoder

код работает, но будьте осторожны: keyWindowэто nilпока главный контроллер представления не назвалviewDidAppear
Casey

9

Я знаю, что это только Свифт решение , но оно может кому-то помочь.

Я имею globals.swiftв каждом проекте, и одна из вещей, которые я всегда добавляю, состоит в том, DeviceTypeчтобы легко обнаружить устройство пользователя:

struct ScreenSize {
  static let width = UIScreen.main.bounds.size.width
  static let height = UIScreen.main.bounds.size.height
  static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
  static let maxWH = max(ScreenSize.width, ScreenSize.height)
}

struct DeviceType {
  static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH < 568.0
  static let iPhone5orSE   = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 568.0
  static let iPhone678     = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 667.0
  static let iPhone678p    = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 736.0
  static let iPhoneX       = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 812.0
  static let iPhoneXRMax   = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 896.0
  static var hasNotch: Bool {
    return iPhoneX || iPhoneXRMax
  }
}

Тогда использовать это:

if DeviceType.hasNotch {
  print("This executes on all phones with a notch")
}

if DeviceType.iPhone678 {
  print("This executes on iPhones 6, 7 and 8")
}

Если вы используете LaunchImageв своем проекте, убедитесь, что добавили изображения для всех поддерживаемых устройств (например, XS Max, XR), потому UIScreen.main.boundsчто без них не будет возвращено правильное значение.


1
Друг, новый для Swift, спросил, как это использовать, на тот случай, если кто-то еще не знает ... if DeviceType.iPhoneX { //do something for iPhone X notch }else{ // don’t do anything about notch }
Лиам Боллинг

5

Все ответы, которые используют, heightявляются только половиной истории по одной причине. Если вы собираетесь проверить таким образом, когда ориентация устройства landscapeLeftили landscapeRightпроверка не удастся, потому heightчтоwidth .

Вот почему мое решение выглядит так в Swift 4.0:

extension UIScreen {
    ///
    static var isPhoneX: Bool {
        let screenSize = UIScreen.main.bounds.size
        let width = screenSize.width
        let height = screenSize.height
        return min(width, height) == 375 && max(width, height) == 812
    }
}

Просто используйте взамен nativeBounds
Leo Dabus

4

Не следует полагать, что единственным устройством, выпущенным Apple с другой высотой UINavigationBar, будет iPhone X. Попробуйте решить эту проблему, используя более общее решение. Если вы хотите, чтобы полоса всегда была на 20px больше высоты по умолчанию, ваш код должен добавить 20px к высоте полосы вместо того, чтобы устанавливать ее на 64px (44px + 20px).


Итак, какое еще решение вы должны предложить?
Стефан Матис

@xaphod есть лучшие ответы сейчас.
Cœur

4
struct ScreenSize {
    static let width = UIScreen.main.bounds.size.width
    static let height = UIScreen.main.bounds.size.height
    static let maxLength = max(ScreenSize.width, ScreenSize.height)
    static let minLength = min(ScreenSize.width, ScreenSize.height)
    static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
}

struct DeviceType {
    static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength < 568.0
    static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 568.0
    static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 667.0
    static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 736.0
    static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 812.0

    static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1024.0
    static let IS_IPAD_PRO          = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1366.0
}

4

Свифт 3 + 4:

без необходимости какого-либо размера пикселя устройства

//UIApplication+SafeArea.swift

extension UIApplication { 

    static var isDeviceWithSafeArea:Bool {

        if #available(iOS 11.0, *) {
            if let topPadding = shared.keyWindow?.safeAreaInsets.bottom,
                topPadding > 0 {
                return true
            }
        }

        return false
    }
}

Пример:

if UIApplication.isDeviceWithSafeArea {
     //e.g. change the frame size height of your UITabBar
}

3
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)

2
он вернет вам 812, если вы загрузите изображение по умолчанию для iPhone X. До тех пор, я думаю, он вернет вам размер iPhone 7, хотя не уверен ...
Фахим Паркар

3
- (BOOL)isIphoneX {
    if (@available(iOS 11.0, *)) {
        UIWindow *window = UIApplication.sharedApplication.keyWindow;
        CGFloat topPadding = window.safeAreaInsets.top;
        if(topPadding>0) {
            return YES;
        }
        else {
            return NO;
        }
    }
    else {
        return NO;
    }
}

1
Лучший ответ! Без необходимости какого-либо размера пикселя устройства.
Питер Крейнз

3

Обычно это нужно программисту для ограничения сверху или снизу, поэтому эти методы могут помочь

static func extraTop() -> CGFloat {

    var top: CGFloat = 0

    if #available(iOS 11.0, *) {

        if let t = UIApplication.shared.keyWindow?.safeAreaInsets.top {
            top = t
        }
    }
    return top
}

static func extraBottom() -> CGFloat {

    var bottom: CGFloat = 0

    if #available(iOS 11.0, *) {

        if let b = UIApplication.shared.keyWindow?.safeAreaInsets.bottom {
            bottom = b
        }
    }
    return bottom
}

Для до iPhone X эти методы возвращают: 0

Для iPhone X: 44 и 34 соответственно

Затем просто добавьте эти дополнения к верхним или нижним ограничениям


3

Для тех, кто получает 2001px вместо 2436px для собственной высоты границ (как я), это потому, что вы создали свое приложение с более старым SDK, до iOS 11 (Xcode 8 вместо Xcode 9). В более старом SDK iOS будет отображать приложения «в черной рамке» на iPhone X вместо того, чтобы расширять экран от края до края, за верхнюю «отметку сенсора». Это уменьшает размер экрана, поэтому это свойство возвращает 2001 вместо 2436.

Самое простое решение - просто проверить оба размера, если вас интересует только обнаружение устройства. Я использовал этот метод для определения FaceID при сборке со старым Xcode SDK, который не имеет значения ENUM, указывающего биометрический тип. В этой ситуации обнаружение устройства с использованием высоты экрана казалось лучшим способом узнать, было ли у устройства FaceID против TouchID без необходимости обновления Xcode.


3

НЕ используйте размер пикселя экрана, как предлагали другие решения, это плохо, поскольку это может привести к ложным срабатываниям для будущих устройств; не будет работать, если UIWindow еще не визуализировал (AppDelegate), не будет работать в ландшафтных приложениях и может не работать на симуляторе, если установлен масштаб.

Вместо этого я создал макрос для этой цели, он очень прост в использовании и использует аппаратные флаги для предотвращения вышеупомянутых проблем.

Изменить: Обновлено для поддержки iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max


Использовать:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

Да, действительно.


Macro:

Просто скопируйте и вставьте это куда угодно, я предпочитаю самый низ моего .h файла после @end

#import <sys/utsname.h>

#if TARGET_IPHONE_SIMULATOR
#define IS_SIMULATOR YES
#else
#define IS_SIMULATOR NO
#endif

#define IS_DEVICE_IPHONEX (\
(^BOOL (void){\
NSString *__modelIdentifier;\
if (IS_SIMULATOR) {\
__modelIdentifier = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];\
} else {\
struct utsname __systemInfo;\
uname(&__systemInfo);\
__modelIdentifier = [NSString stringWithCString:__systemInfo.machine encoding:NSUTF8StringEncoding];\
}\
NSString *__iPhoneX_GSM_Identifier = @"iPhone10,6";\
NSString *__iPhoneX_CDMA_Identifier = @"iPhone10,3";\
NSString *__iPhoneXR_Identifier = @"iPhone11,8";\
NSString *__iPhoneXS_Identifier = @"iPhone11,2";\
NSString *__iPhoneXSMax_China_Identifier = @"iPhone11,6";\
NSString *__iPhoneXSMax_Other_Identifier = @"iPhone11,4";\
return ([__modelIdentifier isEqualToString:__iPhoneX_GSM_Identifier] || [__modelIdentifier isEqualToString:__iPhoneX_CDMA_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXR_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXS_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_China_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_Other_Identifier]);\
})()\
)

Единственная причина, по которой я могу подумать о том, чтобы обнаружить iPhoneX, - это избежать выемки в верхней части экрана; Если это так, вы можете проверить safeArea.top, чтобы определить размер указанной метки. Просто убедитесь, что вы измеряете его после загрузки UIWindow, поэтому не во время viewDidLoad, а через один цикл потока после:if (@available(iOS 11.0, *)) { [UIApplication sharedApplication].keyWindow.safeAreaInsets.top }
Альберт Реншоу

2

Я подробно остановился на ваших ответах и ​​быстро расширил UIDevice. Мне нравятся быстрые перечисления и "все в порядке" и атомизированные. Я создал решение, которое работает как на устройстве, так и на симуляторе.

Преимущества: - простой интерфейс, использование, например, UIDevice.current.isIPhoneX - UIDeviceModelTypeenum дает вам возможность легко расширять специфические особенности модели и константы, которые вы хотите использовать в своем приложении, например cornerRadius.

Недостаток: - это решение для конкретной модели, а не для конкретного разрешения - например, если Apple выпустит другую модель с такими же характеристиками, это не будет работать правильно, и вам нужно добавить другую модель, чтобы это работало => вам необходимо обновить приложение.

extension UIDevice {

    enum UIDeviceModelType : Equatable {

        ///iPhoneX
        case iPhoneX

        ///Other models
        case other(model: String)

        static func type(from model: String) -> UIDeviceModelType {
            switch model {
            case "iPhone10,3", "iPhone10,6":
                return .iPhoneX
            default:
                return .other(model: model)
            }
        }

        static func ==(lhs: UIDeviceModelType, rhs: UIDeviceModelType) -> Bool {
            switch (lhs, rhs) {
            case (.iPhoneX, .iPhoneX):
                return true
            case (.other(let modelOne), .other(let modelTwo)):
                return modelOne == modelTwo
            default:
                return false
            }
        }
    }

    var simulatorModel: String? {
        guard TARGET_OS_SIMULATOR != 0 else {
            return nil
        }

        return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"]
    }

    var hardwareModel: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let model = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        return model
    }

    var modelType: UIDeviceModelType {
        let model = self.simulatorModel ?? self.hardwareModel
        return UIDeviceModelType.type(from: model)
    }

    var isIPhoneX: Bool {
        return modelType == .iPhoneX
    }
}

Вместо использования Mirrorбудет быстрее использовать, sysctlbynameкак в ответе Cloud9999Strife (и в моем ответе тоже).
Cœur

2

Я полагаюсь на высоту строки состояния строки состояния, чтобы определить, является ли это iPhone X:

if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
    // It is an iPhone X
}

Это для приложения и портрета. Вы также можете проверить размер в соответствии с ориентацией устройства. Кроме того, на других iPhone, строка состояния может быть скрыта, поэтому высота кадра 0. На iPhone X строка состояния никогда не скрывается.


Вы можете скрыть строку состояния iPhoneX controllerс помощью этого: - (BOOL)prefersStatusBarHidden { return YES; } Тогда высота строки состояния равна 0.
星辰 夜 之 星辰

@ 无 夜 之 星辰 Я проверяю это во время загрузки в AppDelegate.
Tiois

2

Я использовал код Питера Крейнца (потому что он был чистым и делал то, что мне было нужно), но потом я понял, что он работает только тогда, когда устройство находится в портретном режиме (поскольку верхнее заполнение будет сверху), поэтому я создал расширение для обработки всех ориентации с соответствующими отступами, без учета размера экрана:

extension UIDevice {

    var isIphoneX: Bool {
        if #available(iOS 11.0, *), isIphone {
            if isLandscape {
                if let leftPadding = UIApplication.shared.keyWindow?.safeAreaInsets.left, leftPadding > 0 {
                    return true
                }
                if let rightPadding = UIApplication.shared.keyWindow?.safeAreaInsets.right, rightPadding > 0 {
                    return true
                }
            } else {
                if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 0 {
                    return true
                }
                if let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom, bottomPadding > 0 {
                    return true
                }
            }
        }
        return false
    }

    var isLandscape: Bool {
        return UIDeviceOrientationIsLandscape(orientation) || UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation)
    }

    var isPortrait: Bool {
        return UIDeviceOrientationIsPortrait(orientation) || UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
    }

    var isIphone: Bool {
        return self.userInterfaceIdiom == .phone
    }

    var isIpad: Bool {
        return self.userInterfaceIdiom == .pad
    }
}

И на вашем сайте вызова вы просто:

let res = UIDevice.current.isIphoneX

2

Кроме того, вы можете проверить модуль ' DeviceKit '. После установки все, что вам нужно сделать, чтобы проверить устройство:

import DeviceKit
let device = Device()
if device == .iPhoneX {
  // place your code here
}

2

Ноябрь 2019 г .:

Вот что я использую во всех своих производственных проектах. Обратите внимание, что этот смысл довольно длинный.

  1. Это не использует вычисления ширины или высоты, а скорее:
  2. Проверяет строковую модель устройства.
  3. Отсутствует риск отклонения вашей сборки Apple из-за использования каких-либо частных / недокументированных API.
  4. Работает с симуляторами 💯

    import UIKit
    
    class DeviceUtility {
        /// Determines if the current device of the user is an iPhoneX type/variant.
        static var isIphoneXType: Bool {
            get {
                switch UIDevice().type {
                case .iPhoneXR, .iPhoneXS, .iPhoneXSMax, .iPhoneX, .iPhone11, .iPhone11Pro, .iPhone11ProMax: return true
                default: return false
                }
            }
        }
    }
    
    
    public enum DeviceModel : String {
        case simulator     = "simulator/sandbox",
    
        // MARK: - iPods
    
        iPod1              = "iPod 1",
        iPod2              = "iPod 2",
        iPod3              = "iPod 3",
        iPod4              = "iPod 4",
        iPod5              = "iPod 5",
    
        // MARK: - iPads
    
        iPad2              = "iPad 2",
        iPad3              = "iPad 3",
        iPad4              = "iPad 4",
        iPadAir            = "iPad Air ",
        iPadAir2           = "iPad Air 2",
        iPad5              = "iPad 5", //aka iPad 2017
        iPad6              = "iPad 6", //aka iPad 2018
    
        // MARK: - iPad Minis
    
        iPadMini           = "iPad Mini",
        iPadMini2          = "iPad Mini 2",
        iPadMini3          = "iPad Mini 3",
        iPadMini4          = "iPad Mini 4",
    
        // MARK: - iPad Pros
    
        iPadPro9_7         = "iPad Pro 9.7\"",
        iPadPro10_5        = "iPad Pro 10.5\"",
        iPadPro12_9        = "iPad Pro 12.9\"",
        iPadPro2_12_9      = "iPad Pro 2 12.9\"",
    
        // MARK: - iPhones
    
        iPhone4            = "iPhone 4",
        iPhone4S           = "iPhone 4S",
        iPhone5            = "iPhone 5",
        iPhone5S           = "iPhone 5S",
        iPhone5C           = "iPhone 5C",
        iPhone6            = "iPhone 6",
        iPhone6plus        = "iPhone 6 Plus",
        iPhone6S           = "iPhone 6S",
        iPhone6Splus       = "iPhone 6S Plus",
        iPhoneSE           = "iPhone SE",
        iPhone7            = "iPhone 7",
        iPhone7plus        = "iPhone 7 Plus",
        iPhone8            = "iPhone 8",
        iPhone8plus        = "iPhone 8 Plus",
        iPhoneX            = "iPhone X",
        iPhoneXS           = "iPhone XS",
        iPhoneXSMax        = "iPhone XS Max",
        iPhoneXR           = "iPhone XR",
        iPhone11           = "iPhone 11",
        iPhone11Pro        = "iPhone 11 Pro",
        iPhone11ProMax     = "iPhone 11 Pro Max",
    
        // MARK: - Apple TVs
    
        AppleTV            = "Apple TV",
        AppleTV_4K         = "Apple TV 4K",
    
        // MARK: - Unrecognized
    
        unrecognized       = "?unrecognized?"
    }
    
    // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    //MARK: UIDevice extensions
    // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    
    public extension UIDevice {
        var type: DeviceModel {
            var systemInfo = utsname()
            uname(&systemInfo)
            let modelCode = withUnsafePointer(to: &systemInfo.machine) {
                $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                    ptr in String.init(validatingUTF8: ptr)
    
                }
            }
            let modelMap : [ String : DeviceModel ] = [
    
                // MARK: - Simulators
    
                "i386"      : .simulator,
                "x86_64"    : .simulator,
    
                // MARK: - iPod
    
                "iPod1,1"   : .iPod1,
                "iPod2,1"   : .iPod2,
                "iPod3,1"   : .iPod3,
                "iPod4,1"   : .iPod4,
                "iPod5,1"   : .iPod5,
    
                // MARK: - iPad
    
                "iPad2,1"   : .iPad2,
                "iPad2,2"   : .iPad2,
                "iPad2,3"   : .iPad2,
                "iPad2,4"   : .iPad2,
                "iPad3,1"   : .iPad3,
                "iPad3,2"   : .iPad3,
                "iPad3,3"   : .iPad3,
                "iPad3,4"   : .iPad4,
                "iPad3,5"   : .iPad4,
                "iPad3,6"   : .iPad4,
                "iPad4,1"   : .iPadAir,
                "iPad4,2"   : .iPadAir,
                "iPad4,3"   : .iPadAir,
                "iPad5,3"   : .iPadAir2,
                "iPad5,4"   : .iPadAir2,
                "iPad6,11"  : .iPad5, //aka iPad 2017
                "iPad6,12"  : .iPad5,
                "iPad7,5"   : .iPad6, //aka iPad 2018
                "iPad7,6"   : .iPad6,
    
                // MARK: - iPad mini
    
                "iPad2,5"   : .iPadMini,
                "iPad2,6"   : .iPadMini,
                "iPad2,7"   : .iPadMini,
                "iPad4,4"   : .iPadMini2,
                "iPad4,5"   : .iPadMini2,
                "iPad4,6"   : .iPadMini2,
                "iPad4,7"   : .iPadMini3,
                "iPad4,8"   : .iPadMini3,
                "iPad4,9"   : .iPadMini3,
                "iPad5,1"   : .iPadMini4,
                "iPad5,2"   : .iPadMini4,
    
                // MARK: - iPad pro
    
                "iPad6,3"   : .iPadPro9_7,
                "iPad6,4"   : .iPadPro9_7,
                "iPad7,3"   : .iPadPro10_5,
                "iPad7,4"   : .iPadPro10_5,
                "iPad6,7"   : .iPadPro12_9,
                "iPad6,8"   : .iPadPro12_9,
                "iPad7,1"   : .iPadPro2_12_9,
                "iPad7,2"   : .iPadPro2_12_9,
    
                // MARK: - iPhone
    
                "iPhone3,1" : .iPhone4,
                "iPhone3,2" : .iPhone4,
                "iPhone3,3" : .iPhone4,
                "iPhone4,1" : .iPhone4S,
                "iPhone5,1" : .iPhone5,
                "iPhone5,2" : .iPhone5,
                "iPhone5,3" : .iPhone5C,
                "iPhone5,4" : .iPhone5C,
                "iPhone6,1" : .iPhone5S,
                "iPhone6,2" : .iPhone5S,
                "iPhone7,1" : .iPhone6plus,
                "iPhone7,2" : .iPhone6,
                "iPhone8,1" : .iPhone6S,
                "iPhone8,2" : .iPhone6Splus,
                "iPhone8,4" : .iPhoneSE,
                "iPhone9,1" : .iPhone7,
                "iPhone9,3" : .iPhone7,
                "iPhone9,2" : .iPhone7plus,
                "iPhone9,4" : .iPhone7plus,
                "iPhone10,1" : .iPhone8,
                "iPhone10,4" : .iPhone8,
                "iPhone10,2" : .iPhone8plus,
                "iPhone10,5" : .iPhone8plus,
                "iPhone10,3" : .iPhoneX,
                "iPhone10,6" : .iPhoneX,
                "iPhone11,2" : .iPhoneXS,
                "iPhone11,4" : .iPhoneXSMax,
                "iPhone11,6" : .iPhoneXSMax,
                "iPhone11,8" : .iPhoneXR,
                "iPhone12,1" : .iPhone11,
                "iPhone12,3" : .iPhone11Pro,
                "iPhone12,5" : .iPhone11ProMax,
    
                // MARK: - AppleTV
    
                "AppleTV5,3" : .AppleTV,
                "AppleTV6,2" : .AppleTV_4K
            ]
    
            if let model = modelMap[String.init(validatingUTF8: modelCode!)!] {
                if model == .simulator {
                    if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
                        if let simModel = modelMap[String.init(validatingUTF8: simModelCode)!] {
                            return simModel
                        }
                    }
                }
                return model
            }
            return DeviceModel.unrecognized
        }
    }

Использование: let inset: CGFloat = DeviceUtility.isIphoneXType? 50,0: 40,0


Работает отлично. Спасибо. Я использую это в проекте SwiftUI.
LondonGuy

1

Я должен был решить ту же проблему недавно. И хотя на этот вопрос дан окончательный ответ («Нет»), это может помочь тем, кому нужно специфическое поведение макета iPhone X.

Меня не интересовало, было ли это устройство iPhone X. Меня интересовало, имеет ли устройство дисплей с надрезом.

private static var hasNotchedDisplay: Bool {
    if let window = UIApplication.shared.keyWindow {
        return (window.compatibleSafeAreaInsets.top > 20.0 || window.compatibleSafeAreaInsets.left > 0.0 || window.compatibleSafeAreaInsets.right > 0.0)
    }

    return false
}

Вы также можете написать hasOnScreenHomeIndicator переменную в том же ключе (хотя, возможно, проверьте нижнюю безопасную область?).

Выше используется мое расширение UIViewдля удобного доступа к безопасным областям на iOS 10 и более ранних версиях.

@objc public extension UIView {
    @objc public var compatibleSafeAreaInsets: UIEdgeInsets {
        if #available(iOS 11.0, *) {
            return safeAreaInsets
        } else {
            return .zero
        }
    }

    @objc public var compatibleSafeAreaLayoutGuide: UILayoutGuide {
        if #available(iOS 11.0, *) {
            return safeAreaLayoutGuide
        } else {
            return layoutMarginsGuide
        }
    }
}

1

В Портрете только я использую ширину и высоту фрейма функции представления для проверки:

override func viewDidLoad() {
    super.viewDidLoad()

    // iPhone Xr: -414 x 896
    // iPhone Xs Max: -414 x 896
    // iPhone X, Xs: -375 x 812

    if view.frame.width == 414 && view.frame.height == 896 || view.frame.width == 375 && view.frame.height == 812  {

        print("iPhone X")
    } else {

        print("not iPhone X")
    }

}

Размеры портретного экрана приведены здесь

введите описание изображения здесь


0

Есть несколько причин, чтобы узнать, что это за устройство.

  1. Вы можете проверить высоту устройства (и ширину). Это полезно для макета, но вы обычно не хотите делать это, если хотите знать точное устройство.

  2. Для макета вы также можете использовать UIView.safeAreaInsets.

  3. Если вы хотите отобразить имя устройства, например, для включения в электронное письмо для диагностических целей, после получения модели устройства с помощью sysctl (), вы можете использовать эквивалент этого, чтобы вычислить имя:

    $ curl http://appledevicenames.com/devices/iPhone10,6
    
    iPhone X
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.