检测设备是否为 iPhone X/XS/XR 的几种方式

栏目: IOS · 发布时间: 6年前

内容简介:在上一条小集最后我们介绍了一种在代码中通过获取屏幕的高度判断是否等于因此,本条小集重新整理一下我们目前所了解到的几种检测设备是否为 iPhone X 的方式,供大家参考,不足之处欢迎补充。

在上一条小集 《iPhone 屏幕分辨率终极指南》 中,我们整理介绍了目前已发布的所有 iPhone 设备的屏幕数据,包括了最新上市的 iPhone XS、iPhone XS Max 和 iPhone XR。

最后我们介绍了一种在代码中通过获取屏幕的高度判断是否等于 812.0896.0 来检测设备是否为 iPhone X 的方法,但该方法存在小瑕疵,需要考虑一下两点:

  • 当 App 支持横竖屏切换时,在横屏模式下也能够正确判断;
  • 在模拟器中调试时,能够正确判断当前所选则的模拟器类型是不是 iPhone X;

因此,本条小集重新整理一下我们目前所了解到的几种检测设备是否为 iPhone X 的方式,供大家参考,不足之处欢迎补充。

备注:这里所说的 iPhone X 泛指屏幕大小为 5.8、6.1、6.5 英寸三种尺寸,且带有 顶部刘海和底部操作条 的 iPhone 设备。

方式一:通过获取设备的 device model 来判断

每一台 iOS 设备都有对应的硬件编码/标识符,称为 device model 或者叫 machine name ,我们可以通过如下两种方法来获取 device model/machine name。

#import <sys/sysctl.h>
#import <sys/utsname.h>

// 获取 device model/machine name 的方法一
+ (NSString *)machineName1 {
    size_t size;
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    char *machine = (char *)malloc(size);
    if (machine == NULL) {
        return nil;
    }
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];
    free(machine);
    return platform;
}

// 获取 device model/machine name 的方法二
+ (NSString *)machineName2 {
    struct utsname systemInfo;
    uname(&systemInfo);
    return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}

例如,去年发布的第一代 iPhone X 对应的 device mode 为 iPhone10,3iPhone10,6 ,而今年最新发布 iPhone XS 对应 iPhone11,2 ,iPhone XS Max 对应 iPhone11,4iPhone11,6 ,iPhone XR 对应 iPhone11,8 ,完整的 device mode 数据参考这里:

不过需要注意的是,上述两种获取 device model 的方法在模拟器中运行得到的值为 i386x86_64 ,因此在模拟器中我们可以通过如下方式正确获取模拟器所对应的 device model:

// 获取模拟器所对应的 device model
NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];

综上,我们可以通过判断 device model 是否为 “iPhone10,3” 和 “iPhone10,6” 或者以 “iPhone11,”(新设备)开头,来检测设备是否为 iPhone X,完整代码如下:

+ (BOOL)isiPhoneX {
    static BOOL isiPhoneX = NO;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
#if TARGET_IPHONE_SIMULATOR
        // 获取模拟器所对应的 device model
        NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
        // 获取真机设备的 device model
        struct utsname systemInfo;
        uname(&systemInfo);
        NSString *model = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
#endif
        // 判断 device model 是否为 "iPhone10,3" 和 "iPhone10,6" 或者以 "iPhone11," 开头
        // 如果是,就认为是 iPhone X
        isiPhoneX = [model isEqualToString:@"iPhone10,3"] || [model isEqualToString:@"iPhone10,6"] || [model hasPrefix:@"iPhone11,"];
    });
    
    return isiPhoneX;
}

方式二:通过获取屏幕的宽高来判断

正如我们前一条小集讲到,目前 iPhone X 设备的屏幕宽高对应的开发尺寸只有两种,分别为 375pt * 812pt414pt * 896pt ,因此我们可以根据屏幕的高度来判断设备是否为 iPhone X。但是此时需要考虑设备处于横屏或者竖屏的情况,这两种情况的宽高刚好是相反的(当然,如果你的 App 不用支持横屏的情况,就相对比较简单了)。

UIDevice 中提供了一个 orientation 属性用于获取设备的方向(横向、竖向、或者水平),一开始我们想着先通过这个属性判断设备处于横屏或者竖屏,然后分别取其对应的屏幕宽度(横屏下)或者高度(竖屏下)来判断,但是当这个属性的值为 FaceUp 或者 FaceDown (即设备放在水平面上),我们是无法知道此时设备是处于横屏还是竖屏的。

后面我们想了一个简便的方法,即获取屏幕的宽度和高度,取较大一方进行比较是等于 812.0896.0 ,代码如下:

+ (BOOL)isiPhoneX {
    // 先判断当前设备是否为 iPhone 或 iPod touch
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        // 获取屏幕的宽度和高度,取较大一方判断是否为 812.0 或 896.0
        CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
        CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
        CGFloat maxLength = screenWidth > screenHeight ? screenWidth : screenHeight;
        if (maxLength == 812.0f || maxLength == 896.0f) {
            return YES;
        }
    }
    return NO;
}

方式三:通过底部安全区域的高度来判断

在去年 iPhone X 发布后,为了适配顶部的浏览和底部的操作条,苹果在 iOS 11 上引入安全区域概念,建议开发者在安全区域内进行 UI 布局,因此我们可以获取屏幕 keyWindow 的 safeAreaInsets 值来判断设备是否 iPhone X。

iPhone X 在竖屏下,keyWindow 的 safeAreaInsets 值为:

{top: 44, left 0, bottom: 34, right: 0}

而在横屏下,其值为:

{top: 0, left 44, bottom: 21, right: 44}

因此,我们可以比较 safeAreaInsetsbottom 是否等于 34.0 或者 21.0 来判断设备是否为 iPhone X,因为其他设备对应的 bottom 横竖屏下都为 0 ,代码如下:

+ (BOOL)isiPhoneX {
    if (@available(iOS 11.0, *)) {
        UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
        // 获取底部安全区域高度,iPhone X 竖屏下为 34.0,横屏下为 21.0,其他类型设备都为 0
        CGFloat bottomSafeInset = keyWindow.safeAreaInsets.bottom;
        if (bottomSafeInset == 34.0f || bottomSafeInset == 21.0f) {
            return YES;
        }
    }
    return NO;
}

不过该方式有个不足是,必须在 AppDelegate 的 didFinishLaunchingWithOptions 回调中等 keyWindow 初始化之后才能正确判断。

方式四:通过是否支持 FaceID 判断

由于目前只有 iPhone X 设备支持 FaceID,因此我们也可以通过判断设备是否支持 FaceID 来判断,代码如下:

+ (BOOL)canUseFaceID {
    if (@available(iOS 11.0, *)) {
        // will fail if user denies `canEvaluatePolicy:error:`
        LAContext *context = [[LAContext alloc] init];
        if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil]) {
            return (context.biometryType == LABiometryTypeFaceID);
        }
    }
    return NO;
}

不足:如果用户禁用 canEvaluatePolicy:error: 方法的使用将无法正确判断。

方式五:通过 UIStatusBar 的高度判断

在 iPhone X 之前,所有 iPhone 设备的 StatusBar(状态栏)高度都为 20pt ,而 iPhone X 的为 44pt ,因此我们可以通过获取状态栏的高度判断是否等于 44.0 来检测设备是否为 iPhone X,代码如下:

+ (BOOL)isiPhoneX {
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
    if (statusBarFrame.size.height == 44.0f) {
        return YES;
    }
    return NO;
}

不足:该方法只适用于竖屏且显示状态栏的情况下才能正确检测,而在横屏模式下,或者 App 隐藏导航栏时,获取到的状态栏高度都为 0statusBarFrame 的值为 CGRectZero ),就无法判断了。

你是否有其他判断方式呢?欢迎补充~


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

技术的本质

技术的本质

布莱恩•阿瑟(Brian Arthur) / 曹东溟、王健 / 浙江人民出版社 / 2014-4-1 / 62.90

★《技术的本质》是复杂性科学奠基人、首屈一指的技术思想家、“熊彼特奖”得主布莱恩•阿瑟所创建的一套关于技术产生和进化的系统性理论,本书是打开“技术黑箱”的钥匙,它用平实的语言将技术最本质的思想娓娓道来。 ★技术,是一个异常美丽的主题,它不动声色地创造了我们的财富,成就了经济的繁荣,改变了我们存在的方式。尽管技术如此重要,却少有人在快节奏的生活中停下来深入思考技术。我们了解技术的原理,却不知道......一起来看看 《技术的本质》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具