检测设备是否为 iPhone X

Detect if the device is iPhone X

我的 iOS 应用程序为 UINavigationBar 使用了自定义高度,这会导致新的 iPhone X 出现一些问题。

是否有人已经知道如何可靠 以编程方式(在 Objective-C 中)检测某个应用是否在 iPhone X 上 运行?

编辑:

当然可以检查屏幕的大小,但是,我想知道是否有一些 "build in" 方法,例如 TARGET_OS_IPHONE 来检测 iOS...

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

编辑 2:

我不认为我的问题是链接问题的重复。当然,有一些方法可以 "measure" 当前设备的不同属性,并根据结果来决定使用哪个设备。但是,这不是我在第一次编辑中试图强调的问题的实际要点。

实际问题是:"Is it possible to directly detect if the current device is an iPhone X (e.g. by some SDK feature) or do I have to use indirect measurements"?

根据目前给出的答案,我假设答案是"No, there is no direct methods. Measurements are the way to go"。

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

根据你的问题,答案是否定的。没有直接的方法。如需更多信息,您可以在此处获取信息:

  • How to get device make and model on iOS?

  • how to check screen size of iphone 4 and iphone 5 programmatically in swift

iPhone X 高度为 2436 像素

来自 Device Screen Sizes and resolutions:

来自 Device Screen Sizes and Orientations:

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

Objective-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:
            case 2208:
                printf("iPhone 6+/6S+/7+/8+");
                break;

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

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

            case 1792:
                printf("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 人机界面指南中的以下页面:

Swift:

topNotch检测:

If anyone considering using notch to detect iPhoneX, mind that on "landscape" its same for all iPhones.

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

    return false
}

Objective-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 属性 来识别设备类型,正如 documentation for userInterfaceIdiom 解释的那样:

For universal applications, you can use this property to tailor the behavior of your application for a specific type of device. For example, iPhone and iPad devices have different screen sizes, so you might want to create different views and controls based on the type of the current device.

也就是说,这个属性只是用来标识运行应用的视图风格。但是,iPhone 应用程序(非通用)可以通过应用程序商店安装在 iPad 设备中,在这种情况下,userInterfaceIdiom 将 return UIUserInterfaceIdiomPhone ,也是。

正确的方法是通过uname获取机器名。详情请查看以下内容:

  • How to get device make and model on iOS?

是的,这是可能的。 下载 UIDevice-Hardware extension(或通过 CocoaPod 'UIDevice-Hardware' 安装)然后使用:

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

请注意,这在模拟器中不起作用,只能在实际设备上起作用。

另一种可能性,它适用于 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;
        }
    }

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
}

当然,如果您是横向的,您可能需要检查左右安全区域插图。

编辑:_window 是 AppDelegate 的 UIWindow,此检查在应用程序 didFinishLaunchingWithOptions 中完成。

已更新 iOS 12 的答案以检查 top > 24 而不是 top > 0。

编辑:在模拟器中,您可以转到硬件,切换通话状态栏。这样做表明状态栏高度在 iPhone X on iOS 11 或 iPhone XS iOS 12 通话时不会改变。在这两种情况下,所有的变化都是时间图标,它的背景都是绿色的。这是一个快照:

你可以这样做来根据维度检测iPhone X设备。

Swift

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

Objective - C

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

但是,

这还不够。如果 Apple 宣布下一个 iPhone 具有相同的 iPhone X 尺寸怎么办。所以最好的方法是使用硬件字符串来检测设备。

对于较新的设备硬件字符串如下。

iPhone 8 - iPhone10,1iPhone 10,4

iPhone 8 加 - iPhone10,2iPhone 10,5

iPhone X - iPhone10,3iPhone10,6

您不应假定 Apple 发布的唯一具有不同 UINavigationBar 高度的设备将是 iPhone X。请尝试使用更通用的解决方案来解决此问题。如果您希望栏始终比其默认高度大 20px,您的代码应该将栏的高度增加 20px,而不是将其设置为 64px (44px + 20px)。

所有这些基于尺寸的答案都容易在未来的设备上出现不正确的行为。他们今天会工作,但如果明年有一个 iPhone 大小相同但在玻璃下面有相机等,所以没有 "notch?" 如果唯一的选择是更新应用程序,那么这对您和您的客户来说都是一个糟糕的解决方案。

您还可以检查硬件型号字符串,例如 "iPhone10,1",但这是有问题的,因为有时 Apple 会针对全球不同的运营商发布不同的型号。

正确的做法是重新设计顶部布局,或者解决您在自定义导航栏高度方面遇到的问题(这是我关注的重点)。但是,如果你决定不做这些事情中的任何一件,请意识到无论你做什么都是为了让这个工作今天,并且您需要在某个时候更正它,也许需要多次更正,以保持 hacks 正常工作。

根据@saswanb 的回复,这是 Swift 4 版本:

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

查看the device model / machine name, DO NOT use the point/pixel count in your code directly, it's hard code对设备硬件无意义,设备型号是一类设备匹配的唯一唯一标识符

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

参考this answer.

完整代码实现:

#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))
        @"iPhone13,1", @"iPhone13,2", @"iPhone13,3", @"iPhone13,4", // iPhone 12 ([mini]|[Pro (Max)])
    ];

    return [notchiModels containsObject:GetDeviceModel()];
}
#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"]

注意:- 注意,它仅适用于纵向

SWIFT 4+ 答案

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

注:需要真机测试

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")
        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. 您可以检查设备高度(和宽度)。这对布局很有用,但如果您想知道确切的设备,您通常不想这样做。

  2. 出于布局目的,您还可以使用UIView.safeAreaInsets

  3. 如果要显示设备名称,例如,为了诊断目的包含在电子邮件中,在使用 sysctl () 检索设备型号后,您可以使用等效的以此计算名称:

    $ curl http://appledevicenames.com/devices/iPhone10,6
    
    iPhone X
    
- (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;
    }
}

所有使用 height 的答案都只是故事的一半,原因有一个。如果您要在设备方向为 landscapeLeftlandscapeRight 时进行这样的检查,则检查将失败,因为 height 已被 width.[=16 换出=]

这就是为什么我的解决方案在 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
    }
}

我知道这只是一个 Swift 解决方案,但它可以帮助某人。

我在每个项目中都有 globals.swift 一些代码来缓解我的生活,我经常添加的其中一件事是 ScreenSizehasNotch 以轻松检测 phone类型和尺寸:

struct ScreenSize {
  static let width = UIScreen.main.bounds.size.width
  static let height = UIScreen.main.bounds.size.height
}

var hasNotch: Bool {
  return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 0
}

然后使用它:

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

请根据实际需要对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,")

用于面容 ID 支持

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

通常,程序员需要它来约束顶部或底部,因此这些方法可以提供帮助

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 这些方法return: 0

对于iPhone X:相应地为44和34

然后只需将这些额外内容添加到顶部或底部约束

看完所有答案后,我最终这样做了:

解决方案(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 environment platform condition:

检查应用程序在模拟器上是否 运行
#if targetEnvironment(simulator)
    return true
#else
    return false
#endif

(旧方法仍然有效,但这种新方法更适合未来)

我详细阐述了您对其他人的回答,并对 UIDevice 进行了 swift 扩展。我喜欢 swift 枚举和 "everything in order" & 原子化。我创建了适用于设备和模拟器的解决方案。

优点: - 简单的界面,使用例如UIDevice.current.isIPhoneX - UIDeviceModelType enum 使您能够轻松扩展您想要在应用程序中使用的模型特定功能和常量,例如角半径

缺点: - 它是特定于模型的解决方案,而不是特定于分辨率的 - 例如如果 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
    }
}

对于原生边界高度为 2001px 而不是 2436px 的用户(像我一样),这是因为您在 iOS 11 之前(Xcode 8 而不是Xcode 9).使用较旧的 SDK,iOS 将在 iPhone X 上显示应用程序 "black boxed",而不是将屏幕边到边扩展到顶部 "sensor notch" 之外。这减小了屏幕尺寸,这就是 属性 returns 2001 而不是 2436 的原因。

如果您只对设备检测感兴趣,最简单的解决方案是只检查两种尺寸。我在使用没有指定生物识别类型的 ENUM 值的旧 Xcode SDK 构建时使用此方法检测 FaceID。在这种情况下,使用屏幕高度检测设备似乎是了解设备是否具有 FaceID 与 TouchID 而无需更新的最佳方式 Xcode。

我依靠状态栏框架高度来检测它是否是 iPhone X :

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

这是非肖像应用。您还可以根据设备方向检查尺寸。此外,在其他 iPhone 上,状态栏可能会被隐藏,因此框架高度为 0。在 iPhone X 上,状态栏永远不会隐藏。

为了快速修复,我喜欢这个:

let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>

Swift 3 + 4:

without need of any device size pixel value

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

我正在使用 (因为它很干净并且满足了我的需要)但后来我意识到它只在设备处于纵向模式时有效(因为顶部填充显然在顶部) 所以我创建了一个扩展来处理所有方向及其各自的填充,而不依赖于屏幕尺寸:

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

我最近不得不解决同样的问题。虽然这个问题得到了明确的回答 ("No"),但这可能会帮助其他需要 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
        }
    }
}

检测设备是否为 iPhone X 的最好和最简单的方法是,

https://github.com/stephanheilner/UIDevice-DisplayName

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

对于 iPhone X,标识符是 "iPhone10,3" 或 "iPhone10,6"

不要像其他解决方案所建议的那样使用屏幕像素大小,这很糟糕,因为它可能会导致未来设备出现误报;如果 UIWindow 尚未呈现 (AppDelegate),则将无法工作,将无法在横向应用程序中工作,如果设置了比例,则可能会在模拟器上失败。

相反,我为此制作了一个宏,它非常易于使用并且依靠硬件标志来防止上述问题。

编辑:已更新以支持 iPhoneX、iPhone XS、iPhoneXR、iPhoneXS Max


使用:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

是的,真的。


宏:

只需将其复制粘贴到任何地方,我更喜欢 @end

之后我的 .h 文件的最底部
#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]);\
})()\
)

或者,您可以查看“DeviceKit”连播。 安装后,您需要做的就是检查设备:

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

仅纵向中,我使用视图框架的宽度和高度来检查:

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

}

The portrait screen dimensions are listed here

更新

这个答案是旧的,现在 iPhone 系列中有更多 X 系列,您要么必须在 if-else 中列出所有这些维度,要么会容易得多只是检查设备是否有缺口。大约 1.5 年前,我从 SO 的某个地方得到了这个 answer/code。如果我可以 link 我会的代码。

// 1. add an extension to UIDevice with this computed property
extension UIDevice {
    
    var hasTopNotch: Bool {
        if #available(iOS 11.0, tvOS 11.0, *) {
            return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
        }
        return false
    }
} 

// 2. to use in any class
override func viewDidLoad() {
    super.viewDidLoad()

    if UIDevice.current.hasTopNotch {

        print("X series")

    } else {

        print("regular phone")
    }
}

随着 iOS 12 的发布,iPhone X 等设备可能属于此类。

`

extension UIDevice {
    var isPortrait: Bool {

       return UIDeviceOrientationIsPortrait(orientation) ||
      UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)

  }

   var isDeviceWith_XShape : Bool {

    if self.userInterfaceIdiom == .phone {

        if isPortrait
        {
            switch UIScreen.main.nativeBounds.height {

            case 2436,2688,1792:
                print("iPhone X, Xs, Xr, Xs Max")
                return true
            default:
                print("Any other device")
                return false
            }
        }
        else
        {
            switch UIScreen.main.nativeBounds.width {

            case 2436,2688,1792:
                print("iPhone X, Xs, Xr, Xs Max")
                return true
            default:
                print("Any other device")
                return false
            }
        }


    }
    else
    {
        return false
    }

}`

SWIFT 4/5 可重复使用 扩展 iPhone 12支持

    extension UIDevice {
    
    enum `Type` {
        case iPhone_5_5S_5C_SE1
        case iPhone_6_6S_7_8_SE2
        case iPhone_6_6S_7_8_PLUS
        case iPhone_X_XS_12mini
        case iPhone_XR_11
        case iPhone_XS_11Pro_Max
        case iPhone_12_Pro
        case iPhone_12_Pro_Max
    }
    
    var hasHomeButton: Bool {
        switch type {
        case . iPhone_X_XS_12mini, . iPhone_XR_11, .iPhone_XS_11Pro_Max, . iPhone_XS_11Pro_Max, .iPhone_12_Pro, .iPhone_12_Pro_Max:
            return false
        default:
            return true
        }
    }
    
    var type: Type {
        if UI_USER_INTERFACE_IDIOM() == .phone {
        switch UIScreen.main.nativeBounds.height {
        case 1136:
            return .iPhone_5_5S_5C_SE1
        case 1334:
            return .iPhone_6_6S_7_8_SE2
        case 1920, 2208:
            return .iPhone_6_6S_7_8_PLUS
        case 2436:
            return .iPhone_X_XS_12mini
        case 2532:
            return .iPhone_12_Pro
        case 2688:
            return .iPhone_XS_11Pro_Max
        case 2778:
            return .iPhone_12_Pro_Max
        case 1792:
            return .iPhone_XR_11
        default:
            assertionFailure("Unknown phone device detected!")
            return .iPhone_6_6S_7_8_SE2
        }
    } else {
        assertionFailure("Unknown idiom device detected!")
        return .iPhone_6_6S_7_8_SE2
    }
   }
}

使用简单的方法检测任何设备。如下所示,

func isPhoneDevice() -> Bool {
    return UIDevice.current.userInterfaceIdiom == .phone
}

func isDeviceIPad() -> Bool {
    return UIDevice.current.userInterfaceIdiom == .pad
}

func isPadProDevice() -> Bool {
    let SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width
    let SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .pad && SCREEN_MAX_LENGTH == 1366.0
}

func isPhoneXandXSDevice() -> Bool {
    let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
    let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 812.0
}

func isPhoneXSMaxandXRDevice() -> Bool {
    let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
    let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 896.0
}

然后这样调用,

if isPhoneDevice() {
     // Your code
}

我认为 Apple 不希望我们手动检查设备是否有 "notch" 或 "home indicator" 但有效的代码是:

-(BOOL)hasTopNotch{

    if (@available(iOS 11.0, *)) {

        float max_safe_area_inset = MAX(MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right),MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left));

        return max_safe_area_inset >= 44.0;

    }

    return  NO;

}

-(BOOL)hasHomeIndicator{

    if (@available(iOS 11.0, *)) {

        int iNumberSafeInsetsEqualZero = 0;

        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left == 0.0)iNumberSafeInsetsEqualZero++;

        return iNumberSafeInsetsEqualZero <= 2;

    }

    return  NO;

}

其他一些帖子不起作用。例如,纵向模式下带有 "in-call status bar"(绿色条)的 iPhone 6S 有一个大顶部保险柜。使用我的代码,所有情况都被处理了(即使设备以纵向或横向启动

2019 年 11 月:

这是我在所有生产项目中使用的内容。请注意,这个要点很长。

  1. 这不使用宽度或高度的计算,而是:
  2. 它检查设备字符串模型。
  3. 没有因为使用任何私有/未记录的 API 而导致您的构建被 Apple 拒绝的风险。
  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) {
                [=10=].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
        }
    }
    

用法:让插图:CGFloat = DeviceUtility.isIphoneXType ? 50.0 : 40.0

我正在努力使之前的回复发挥作用,其中 none 对我有用。所以我为 SwiftUI 找到了一个解决方案。创建名为 UIDevice+Notch.swift

的文件

及其内容:

extension UIDevice {
    var hasNotch: Bool {
        let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
        return bottom > 0
    }
}

用法:

if UIDevice.current.hasNotch {
    //... consider notch 
} else {
    //... don't have to consider notch 
}

Objective-C.

中有两个宏供需要的人使用
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 24.0)

用法:

if (IS_IPHONE_X) {
}

希望对大家有所帮助

如何检测iOS设备型号和屏幕尺寸?

CheckDevice 检测当前设备型号和屏幕尺寸。

您也可以使用

CheckDevice.size() 返回 iPhone 12 mini's .screen5_4Inch

等... 也许...

CheckDevice.isPhone()

检查设备类型iPhone。

CheckDevice.isWatch()

CheckDevice.isSimulator()

CheckDevice.isPad()

很好的回购

检查设备 https://github.com/ugurethemaydin/CheckDevice