Detect if the device is iPhone X
Based on your question, the answer is no. There are no direct methods. For more information you can get the information here:
- How to get device make and model on iOS?
and
- how to check screen size of iphone 4 and iphone 5 programmatically in swift
The iPhone X height is 2436 px
From Device Screen Sizes and resolutions:
From Device Screen Sizes and Orientations:
Swift 3 and later:
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");
}
}
Based on your question as follow:
Or use screenSize.height
as float 812.0f
not 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");
}
For more information you can refer the following page in iOS Human Interface Guidelines:
- Adaptivity and Layout - Visual Design - iOS - Human Interface Guidelines
Swift:
Detect with 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 {$0.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;
}
UPDATE:
Do not use the userInterfaceIdiom
property to identify the device type, as the documentation for userInterfaceIdiom explains:
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.
That is, this property is just used to identify the running app's view style. However, the iPhone app (not the universal) could be installed in iPad device via App store, in that case, the userInterfaceIdiom
will return the UIUserInterfaceIdiomPhone
, too.
The right way is to get the machine name via uname
. Check the following for details:
- How to get device make and model on iOS?
Another possibility, which works on iOS 11 and iOS 12 because the iPhone X is the only one with a notch at the top and an inset of 44. That is what I am really detecting here:
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
}
And of course, you might need to check the left and right safe area insets if you are in landscape orientation.
Edit: _window is the UIWindow of the AppDelegate, where this check is done in application didFinishLaunchingWithOptions.
Answer updated for iOS 12 to check if top > 24 rather than top > 0.
Edit: In the simulator you can go to Hardware, Toggle In-call Status Bar. Doing that shows me that the status bar height does not change on iPhone X on iOS 11 or iPhone XS iOS 12 when engaged in a call. All that changes is the time icon, which gets a green background, in both cases. Here's a snap:
You shall perform different detections of iPhone X depending on the actual need.
for dealing with the top notch (statusbar, navbar), etc.
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
}
for dealing with the bottom home indicator (tabbar), etc.
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
}
for backgrounds size, fullscreen features, etc.
class var isIphoneXOrBigger: Bool {
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height >= 812
}
Note: eventually mix it with UIDevice.current.userInterfaceIdiom == .phone
Note: this method requires to have a LaunchScreen storyboard or proper LaunchImages
for backgrounds ratio, scrolling features, etc.
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
}
Note: this method requires to have a LaunchScreen storyboard or proper LaunchImages
for analytics, stats, tracking, etc.
Get the machine identifier and compare it to documented values:
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"
}
To include the simulator as a valid iPhone X in your analytics:
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"
}
To include iPhone XS, XS Max and XR, simply look for models starting with "iPhone11,":
return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")
for faceID support
import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
if #available(iOS 11.0, *) {
return LAContext().biometryType == .typeFaceID
}
return false
}
You can do like this to detect iPhone X device according to dimension.
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
}
But,
This is not sufficient way. What if Apple announced next iPhone with same dimension of iPhone X. so the best way is to use Hardware string to detect the device.
For newer device Hardware string is as below.
iPhone 8 - iPhone10,1 or iPhone 10,4
iPhone 8 Plus - iPhone10,2 or iPhone 10,5
iPhone X - iPhone10,3 or iPhone10,6
Check out the device model / machine name, DO NOT use the point/pixel count in your code directly, it's hard code and meaningless for the device hardware, the device model is the only unique identifier for a type of device to match.
#import <sys/utsname.h>
NSString* deviceName()
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
Result:
@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)
Refer to this answer.
Full code implementation:
#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()];
}