我的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功能),还是我必须使用间接测量?”

根据目前给出的答案,我假设答案是“不,没有直接的方法。测量是要走的路。”


当前回答

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

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

其他回答

我详细阐述了你对其他人的回答,并在UIDevice上进行了快速扩展。我喜欢快速枚举和“一切有序”&原子化。我已经创建了解决方案,工作在设备和模拟器。

优点: -界面简单,使用方法如UIDevice.current.isIPhoneX - UIDeviceModelType enum让你能够轻松地扩展模型特定的特性和你想在你的应用中使用的常量,例如拐角半径

劣势: -这是特定于型号的解决方案,而不是特定于分辨率的解决方案-例如,如果苹果将生产另一种具有相同规格的型号,这将无法正常工作,你需要添加另一种型号才能使其工作=>你需要更新你的应用程序。

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

你不应该假设苹果发布的唯一具有不同UINavigationBar高度的设备将是iPhone x。尝试使用更通用的解决方案来解决这个问题。如果你想让条形图总是比默认高度大20px,你的代码应该为条形图的高度增加20px,而不是将其设置为64px (44px + 20px)。

检查设备型号/机器名称,不要在你的代码中直接使用点/像素计数,这是硬代码,对设备硬件没有意义,设备型号是设备类型匹配的唯一标识符。

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

    return [notchiModels containsObject:GetDeviceModel()];
}

检测设备是否为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)))}

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

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