检测设备是否为iPhone X.

mqui 发布于 2019-10-29 ios 最后更新 2019-10-29 22:09 76 浏览

我的iOS应用程序使用UINavigationBar的自定义高度,这会导致新的iPhone X出现一些问题。 如果某个应用程序在iPhone X上运行,是否有人已经知道如何以编程方式可靠地检测(在Objective-C中)? 编辑: 当然,检查屏幕大小是可能的,但是我想知道是否有像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功能)还是必须使用间接测量”? 通过迄今给出的答案,我认为答案是“不,没有直接的方法,测量是要走的路”。
已邀请:

gminus

赞同来自:

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

NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];
请注意,这在模拟器中不起作用,仅在实际设备上有效。

benim

赞同来自:

我知道它只是一个Swift解决方案,但它可以帮助某人。 我在每个项目中都有globals.swift,我总是在其中添加的一件事是DeviceType来快速检测用户的设备:

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
}
它可能是由其他一些StackOverflow答案组成的,因为我得到了所有好东西!

tiste

赞同来自:

您应根据实际需要对iPhone X执行不同的检测。

用于处理顶级(状态栏,导航栏)或底部主页指示符(tabbar)等
class var hasSafeAreaInsets: Bool {
    if #available(iOS 11.0, tvOS 11.0, *) {
        return UIApplication.shared.delegate?.window??.safeAreaInsets != .zero
    }
    return false
}

用于背景大小,全屏功能等
class var isIphoneXOrBigger: Bool {
    return UIScreen.main.bounds.height >= 812
}
注意:最终将其与UIDevice.current.userInterfaceIdiom == .phone
混合使用 注意:此方法需要具有LaunchScreen故事板或正确的LaunchImages

用于背景比例,滚动功能等
class var isIphoneXOrLonger: Bool {
    return UIScreen.main.bounds.height / UIScreen.main.bounds.width >= 812.0 / 375.0
}
注意:此方法需要具有LaunchScreen故事板或正确的LaunchImages

用于分析,统计,跟踪等 获取机器标识符并将其与记录的值进行比较:
class var isIphoneX: Bool {
    var size = 0
    sysctlbyname("hw.machine", nil, &size, nil, 0)
    var machine = CChar
    sysctlbyname("hw.machine", &machine, &size, nil, 0)
    var 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
        sysctlbyname("hw.machine", &machine, &size, nil, 0)
        model = String(cString: machine)
    }
    return model == "iPhone10,3" || model == "iPhone10,6"
}

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

set

赞同来自:

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

tut

赞同来自:

另一种可能性,目前正在运作,因为iPhone X是唯一一个在顶部有缺口的人。这就是我在这里真正发现的:

    iphoneX = NO;
    if (@available(iOS 11.0, *)) {
        if (_window.safeAreaInsets.top > 0.0) {
            iphoneX = YES;
        }
    }
当然,如果您处于横向方向,则可能需要检查左右安全区域插图。 编辑:_window是AppDelegate的UIWindow,其中此检查在应用程序didFinishLaunchingWithOptions中完成。

dipsam

赞同来自:

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

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

zcum

赞同来自:

看完所有答案后,这就是我最终做的事情:

解决方案(兼容Swift 4)
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
            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
}

malias

赞同来自:

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

zvelit

赞同来自:

根据您的问题,答案是否,没有直接方法,有关更多信息,您可以从here1here2获取信息 如果你想检测iphone X高度使用2436px 设备屏幕大小和方向 enter image description here 迅速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 2208:
            print("iPhone 6+/6S+/7+/8+")
        case 2436:
            print("iPhone X")
        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 2208:
                printf("iPhone 6+/6S+/7+/8+");
                break;
            case 2436:
                printf("iPhone X");
                break;
            default:
                printf("unknown");
        }
    }
根据您的问题如下 或使用screenSize.height作为浮动812.0f而不是812
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    if (screenSize.height == 812.0f)
        NSLog(@"iPhone X");
}
有关更多信息,您可以获得here UPDATE 请勿使用userInterfaceIdiom属性来识别设备类型,如Apple文档所述,
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应用程序(不是通用)可以通过App store安装在iPad设备中,在这种情况下,userInterfaceIdiom也会返回UIUserInterfaceIdiomPhone。 正确的方法是通过uname获取机器名称,查看this thread了解详细信息。

inemo

赞同来自:

所有这些基于维度的答案都容易受到未来设备上的错误行为的影响。他们今天会工作,但是如果明年有一部iPhone有相同的尺寸,但玻璃下面有相机等,那么没有“缺口”呢?如果唯一的选择是更新应用程序,那么对您和您的客户来说,这是一个糟糕的解决方案。 您还可以检查硬件型号字符串,如“iPhone10,1”,但这有问题,因为有时Apple会为全球不同的运营商发布不同的型号。 正确的方法是重新设计顶层布局,或者解决自定义导航栏高度所遇到的问题(这就是我所关注的)。但是,如果你决定不做其中任何一件事,那么你应该意识到,无论你做什么都是为了让它今天起作用,你需要在某些时候纠正它,也许是多次,以保持黑客攻击。加工。

sut

赞同来自:

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
}

nnam

赞同来自:

有几个原因想知道设备是什么。

  1. 您可以检查设备高度(和宽度)。这对于布局非常有用,但如果您想知道确切的设备,通常不希望这样做。
  2. 出于布局目的,您还可以使用UIView.safeAreaInsets
  3. 如果要显示设备名称(例如,要包含在电子邮件中以进行诊断),在使用sysctl ()检索设备模型后,您可以使用等效的名称来表示名称:
    $ curl http://appledevicenames.com/devices/iPhone10,6
    iPhone X
    

nsequi

赞同来自:

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

xhic

赞同来自:

您可以这样做,根据尺寸检测iPhone X设备。 迅速

if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
   //iPhone X
}
目标 - C.
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436)  {
  //iPhone X     
}
enter image description here 但, 这还不够。如果Apple宣布下一代iPhone具有相同尺寸的iPhone X,那么最好的方法是使用硬件字符串来检测设备。 对于较新的设备硬件字符串如下。 iPhone 8 - iPhone10,1或iPhone 10,3 iPhone 8 Plus - iPhone10,2或iPhone 10,4 iPhone X - iPhone10,5或iPhone10,6

tin

赞同来自:

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

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相应 然后只需将这些额外内容添加到顶部或底部约束

oest

赞同来自:

由于一个原因,使用height的所有答案只是故事的一半。如果您要在设备方向为landscapeLeftlandscapeRight时进行检查,则检查将失败,因为heightwidth交换出来。 这就是为什么我的解决方案在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
    }
}

zfugit

赞同来自:

SWIFT 4答案 Mehod 1: 使用window?.safeAreaInsets.top

 var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        if #available(iOS 11.0, *) {
            if (window?.safeAreaInsets.top)! > CGFloat(0.0) || window?.safeAreaInsets != .zero {
                print("iPhone X")
            }
            else {
                print("Not iPhone X")
            }
        }
        return true
    }
方法2: 注意:需要真正的设备进行测试 Reference
      let deviceType = UIDevice.current.modelName
        if deviceType.range(of:"iPhone10,3") != nil || deviceType.range(of:"iPhone10,6") != nil {
            print("iPhone X")
        }
        else {
            print("Not iPhone X")
        }
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
    }
}

xminus

赞同来自:

#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)
#define IS_RETINA        ([[UIScreen mainScreen] scale] == 2.0)
#define IS_IPAD_DEVICE   [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]

ret

赞同来自:

检查the device model / machine name,不要直接使用代码中的点/像素数,它是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>
BOOL IsiPhoneX(void)
{
    static BOOL isiPhoneX = NO;
    static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
#if TARGET_IPHONE_SIMULATOR
        NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
struct utsname systemInfo;
        uname(&systemInfo);
NSString *model = [NSString stringWithCString:systemInfo.machine
                                            encoding:NSUTF8StringEncoding];
#endif
        isiPhoneX = [model isEqualToString:@"iPhone10,3"] || [model isEqualToString:@"iPhone10,6"];
    });
return isiPhoneX;
}