ios - plus - iphone xr




Detecta si el dispositivo es iPhone X (20)

Alternativamente, puede consultar el pod ' DeviceKit '. Una vez instalado, todo lo que necesita hacer para verificar el dispositivo es:

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
}

Mi aplicación iOS utiliza una altura personalizada para UINavigationBar que genera algunos problemas en el nuevo iPhone X.

¿Alguien sabe cómo detectar de manera confiable mediante programación (en Objective-C) si una aplicación se ejecuta en iPhone X?

EDITAR:

Por supuesto, es posible verificar el tamaño de la pantalla, sin embargo, me pregunto si hay algún método " TARGET_OS_IPHONE " como TARGET_OS_IPHONE para detectar iOS ...

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

EDITAR 2:

No creo que mi pregunta sea un duplicado de la pregunta vinculada. Por supuesto, hay métodos para "medir" diferentes propiedades del dispositivo actual y usar los resultados para decidir qué dispositivo se usa. Sin embargo, este no era el punto real de mi pregunta, ya que traté de enfatizar en mi primera edición.

La pregunta real es: "¿Es posible detectar directamente si el dispositivo actual es un iPhone X (por ejemplo, mediante alguna función del SDK) o tengo que usar mediciones indirectas" ?

Según las respuestas dadas hasta ahora, supongo que la respuesta es "No, no hay métodos directos. Las medidas son el camino a seguir".


Confío en la altura del marco de la barra de estado para detectar si se trata de un iPhone X:

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

Esto es para aplicación un retrato. También puede verificar el tamaño de acuerdo con la orientación del dispositivo. Además, en otros iPhones, la barra de estado puede estar oculta, por lo que la altura del marco es 0 . En el iPhone X, la barra de estado nunca está oculta.


Estaba usando el código de Peter Kreinz (porque estaba limpio e hizo lo que necesitaba) pero luego me di cuenta de que funciona justo cuando el dispositivo está en posición vertical (dado que el relleno superior estará en la parte superior, obviamente) Así que creé una extensión para manejar todo orientaciones con sus respectivos rellenos, sin retransmitir en el tamaño de la pantalla:

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
    }
}

Y en su sitio de llamadas simplemente:

let res = UIDevice.current.isIphoneX

Expliqué tus respuestas sobre las de los demás e hice una rápida extensión en UIDevice. Me gustan las enumeraciones rápidas y "todo en orden" y atomizado. He creado una solución que funciona tanto en el dispositivo como en el simulador.

Ventajas: - interfaz simple, uso, por ejemplo UIDevice.current.isIPhoneX - UIDeviceModelType enum le brinda la capacidad de ampliar fácilmente las características y constantes específicas del modelo que desea utilizar en su aplicación, por ejemplo, cornerRadius

Desventaja: es una solución específica del modelo, no una resolución específica, por ejemplo, si Apple producirá otro modelo con las mismas especificaciones, esto no funcionará correctamente y debe agregar otro modelo para que funcione => necesita actualizar su aplicación

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
    }
}

NO use el tamaño de píxel de la pantalla como lo han sugerido otras soluciones, esto es malo ya que puede dar lugar a falsos positivos para dispositivos futuros; no funcionará si UIWindow aún no se ha procesado (AppDelegate), no funcionará en aplicaciones horizontales y puede fallar en el simulador si se establece la escala.

En cambio, hice una macro para este propósito, es muy fácil de usar y se basa en indicadores de hardware para evitar los problemas antes mencionados.

Editar: actualizado para admitir iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max

Usar:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

Sí, de verdad.

Macro:

Simplemente copie y pegue esto en cualquier lugar, prefiero la parte inferior de mi archivo .h después @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]);\
})()\
)

Para aquellos que obtienen 2001px en lugar de 2436px para la altura de los límites nativos (como yo), es porque construiste tu aplicación con un SDK anterior, antes de iOS 11 (Xcode 8 en lugar de Xcode 9). Con un SDK anterior, iOS mostrará las aplicaciones "en caja negra" en el iPhone X en lugar de extender la pantalla de borde a borde, más allá de la "muesca del sensor" superior. Esto reduce el tamaño de la pantalla, por lo que esa propiedad devuelve 2001 en lugar de 2436.

La solución más simple es verificar ambos tamaños si solo está interesado en la detección de dispositivos. Utilicé este método para detectar FaceID mientras construía con un Xcode SDK más antiguo que no tiene el valor ENUM que especifica el tipo biométrico. En esta situación, la detección del dispositivo usando la altura de la pantalla parecía ser la mejor manera de saber si el dispositivo tenía FaceID vs TouchID sin tener que actualizar Xcode.


Tuve que resolver el mismo problema recientemente. Y aunque esta pregunta se responde definitivamente ("No"), esto puede ayudar a otros que necesitan un comportamiento de diseño específico para iPhone X.

No estaba realmente interesado en saber si el dispositivo era iPhone X. Estaba interesado en saber si el dispositivo tenía una pantalla con muescas.

@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
        }
    }
}

También podría escribir una hasOnScreenHomeIndicator variable a lo largo de las mismas líneas (aunque, tal vez, verifique el área segura inferior).

Lo anterior usa mi extensión activada UIView para un acceso conveniente a las inserciones de área segura en iOS 10 y versiones anteriores.

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

Deberá realizar diferentes detecciones de iPhone X según la necesidad real.

para tratar con la muesca superior (barra de estado, barra de navegación), etc.

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
}

para tratar con el indicador de inicio inferior (barra de pestañas), etc.

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
}

para tamaño de fondos, funciones de pantalla completa, etc.

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

Nota: eventualmente mézclelo con UIDevice.current.userInterfaceIdiom == .phone
Nota: este método requiere tener un guión gráfico de LaunchScreen o imágenes de lanzamiento adecuadas

para relación de fondos, funciones de desplazamiento, etc.

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
}

Nota: este método requiere tener un guión gráfico de LaunchScreen o imágenes de lanzamiento adecuadas

para análisis, estadísticas, seguimiento, etc.

Obtenga el identificador de la máquina y compárelo con los valores documentados:

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"
}

Para incluir el simulador como un iPhone X válido en sus análisis:

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"
}

Para incluir iPhone XS, XS Max y XR, simplemente busque modelos que comiencen con "iPhone11":

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

para soporte de 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
}

No debe suponer que el único dispositivo que Apple lanzará con una altura diferente de UINavigationBar será el iPhone X. Intente resolver este problema utilizando una solución más genérica. Si desea que la barra siempre sea 20px más grande que su altura predeterminada, su código debe agregar 20px a la altura de la barra, en lugar de establecerla en 64px (44px + 20px).


Otra posibilidad, que funciona en iOS 11 y iOS 12 porque el iPhone X es el único con una muesca en la parte superior y un recuadro de 44. Eso es lo que realmente estoy detectando aquí:

C objetivo:

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

Swift 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
}

Y, por supuesto, es posible que deba verificar las inserciones del área segura izquierda y derecha si está en orientación horizontal.

Editar: _window es la UIWindow de AppDelegate, donde esta comprobación se realiza en la aplicación didFinishLaunchingWithOptions.

Respuesta actualizada para iOS 12 para verificar si top> 24 en lugar de top> 0.

Editar: en el simulador puede ir a Hardware, Activar barra de estado de llamada entrante. Hacer eso me muestra que la altura de la barra de estado no cambia en el iPhone X en iOS 11 o iPhone XS iOS 12 cuando se realiza una llamada. Todo lo que cambia es el ícono de tiempo, que obtiene un fondo verde, en ambos casos. Aquí hay un complemento:


Puede hacer esto para detectar el dispositivo iPhone X según la dimensión.

Rápido

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

C objetivo

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

Pero

Esto no es suficiente. ¿Qué pasaría si Apple anunciara el próximo iPhone con la misma dimensión que el iPhone X? Entonces, la mejor manera es usar una cadena de hardware para detectar el dispositivo.

Para el dispositivo más nuevo, la cadena de hardware es la siguiente.

iPhone 8 - iPhone10,1 o iPhone 10,4

iPhone 8 Plus - iPhone10,2 o iPhone 10,5

iPhone X - iPhone10,3 o iPhone10,6


Sé que es solo una solución Swift , pero podría ayudar a alguien.

Tengo globals.swift en cada proyecto y una de las cosas que siempre agrego es DeviceType para detectar fácilmente el dispositivo del usuario:

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.maxLength == 896.0
  static var hasNotch: Bool {
    return iPhoneX || iPhoneXRMax
  }
}

Luego para usarlo:

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

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

Si usa LaunchImage en su proyecto, asegúrese de agregar imágenes para todos los dispositivos compatibles (como XS Max, XR) porque UIScreen.main.bounds no devolverá el valor adecuado sin ellos.


Según la respuesta de @ saswanb, esta es una versión de Swift 4:

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

Según su pregunta, la respuesta es no. No hay métodos directos. Para obtener más información, puede obtener la información aquí:

y

La altura del iPhone X es de 2436 px

Desde tamaños de pantalla del dispositivo y resoluciones :

Desde los tamaños y orientaciones de la pantalla del dispositivo :

Swift 3 y posterior :

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")

        case 2688:
            print("iPhone XS Max")

        case 1792:
            print("iPhone XR")

        default:
            print("Unknown")
        }
    }

Objetivo-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:
            printf("iPhone X, XS");
            break;

        case 2688:
            printf("iPhone XS Max");
            break;

        case 1792:
            printf("iPhone XR");
            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");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
        Console.WriteLine("iPhone XS Max");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
        Console.WriteLine("iPhone XR");
    } else {
        Console.WriteLine("Unknown");
    }
}

Basado en su pregunta de la siguiente manera:

O use screenSize.height como float 812.0f no 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");
    }

Para obtener más información, puede consultar la siguiente página en las Directrices de interfaz humana de iOS:

Rápido :

Detectar con topNotch :

var hasTopNotch: Bool {
    if #available(iOS 11.0,  *) {
        return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
    }

    return false
}

Objetivo-C :

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

    return  NO;
}

ACTUALIZACIÓN

No utilice la propiedad userInterfaceIdiom para identificar el tipo de dispositivo, como explica la documentación de userInterfaceIdiom :

Para aplicaciones universales, puede usar esta propiedad para adaptar el comportamiento de su aplicación para un tipo específico de dispositivo. Por ejemplo, los dispositivos iPhone y iPad tienen diferentes tamaños de pantalla, por lo que es posible que desee crear diferentes vistas y controles según el tipo de dispositivo actual.

Es decir, esta propiedad solo se usa para identificar el estilo de vista de la aplicación en ejecución. Sin embargo, la aplicación para iPhone (no la universal) podría instalarse en el dispositivo iPad a través de la tienda de aplicaciones, en ese caso, el userInterfaceIdiom también devolverá el UIUserInterfaceIdiomPhone .

La forma correcta es obtener el nombre de la máquina a través de uname . Verifique lo siguiente para más detalles:


Todas las respuestas que usan la height son solo la mitad de la historia por una razón. Si va a verificar de esa manera cuando la orientación del dispositivo sea landscapeLeft o landscapeRight la verificación fallará, porque la height se intercambia con el width .

Es por eso que mi solución se ve así en 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
    }
}

Verifique el nombre del modelo / máquina del dispositivo , NO use el recuento de puntos / píxeles en su código directamente, es un código duro y no tiene sentido para el hardware del dispositivo.

#import <sys/utsname.h>

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

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

Resultado:

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

Refiérase a esta respuesta .

Implementación de código completo:

#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)
{
    NSString *strModelID = GetDeviceModel();

    return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"] || // iPhone X
           [strModelID isEqualToString:@"iPhone11,2"] || [strModelID isEqualToString:@"iPhone11,4"] || [strModelID isEqualToString:@"iPhone11,6"] || // iPhone XS (Max)
           [strModelID isEqualToString:@"iPhone11,8"]; // iPhone XR
}

Swift 3 + 4:

sin necesidad de ningún valor de píxel de tamaño de dispositivo

//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
    }
}

Ejemplo:

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

SWIFT 4+ Respuesta

iPhone X, XR, XS, XSMAX:

Nota: necesita un dispositivo real para la prueba

Reference

 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")
        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
    }
}

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

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
}




iphone-x