檢測裝置是否為 iPhone X/XS/XR 的幾種方式
在上一條小集ofollow,noindex" target="_blank">《iPhone 螢幕解析度終極指南》 中,我們整理介紹了目前已釋出的所有 iPhone 裝置的螢幕資料,包括了最新上市的 iPhone XS、iPhone XS Max 和 iPhone XR。
最後我們介紹了一種在程式碼中通過獲取螢幕的高度判斷是否等於812.0
或896.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,3
和iPhone10,6
,而今年最新發布 iPhone XS 對應iPhone11,2
,iPhone XS Max 對應iPhone11,4
和iPhone11,6
,iPhone XR 對應iPhone11,8
,完整的 device mode 資料參考這裡:
不過需要注意的是,上述兩種獲取 device model 的方法在模擬器中執行得到的值為i386
或x86_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 * 812pt
和414pt * 896pt
,因此我們可以根據螢幕的高度來判斷裝置是否為 iPhone X。但是此時需要考慮裝置處於橫屏或者豎屏的情況,這兩種情況的寬高剛好是相反的(當然,如果你的 App 不用支援橫屏的情況,就相對比較簡單了)。
在UIDevice
中提供了一個orientation
屬性用於獲取裝置的方向(橫向、豎向、或者水平),一開始我們想著先通過這個屬性判斷裝置處於橫屏或者豎屏,然後分別取其對應的螢幕寬度(橫屏下)或者高度(豎屏下)來判斷,但是當這個屬性的值為FaceUp
或者FaceDown
(即裝置放在水平面上),我們是無法知道此時裝置是處於橫屏還是豎屏的。
後面我們想了一個簡便的方法,即獲取螢幕的寬度和高度,取較大一方進行比較是等於812.0
或896.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}
因此,我們可以比較safeAreaInsets
的bottom
是否等於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 隱藏導航欄時,獲取到的狀態列高度都為0
(statusBarFrame
的值為CGRectZero
),就無法判斷了。
你是否有其他判斷方式呢?歡迎補充~