Identify iPhones with Notch Programmatically
Asked Answered
T

3

10

I am trying to identify iPhones with the notch programmatically. I am aware of the screen.size method, but when you have a universal app supporting all interface orientations, it becomes a mess (counting all the possible variations). So I am looking for a simpler and more elegant way to detect the newer iPhones X models.

I have stumbled upon a method online that is supposed to work. In it, you measure the bottom inset of the safe area and if it is not zero, you have an iPhone X model. This makes sense in theory since, the safe area does not reach the bottom of the screen on the iPhone X handsets but does on all other devices. I do the check this way:

if (@available( iOS 11.0, * )) {
    if ([[[UIApplication sharedApplication] keyWindow] safeAreaInsets].bottom > 0) {
        // iPhone with notch
    }
} else {
    // Regular iPhone
}

This, however, does not work. Can someone point out my mistake in the implementation or confirm if this method is even viable?

Terr answered 16/4, 2019 at 19:28 Comment(3)
Why are you trying to detect the notch? There should be no need to do so. Use proper constraints and things will work as expected.Specialist
Just translate it: medium.com/@cafielo/…Denham
@KarloA.López, that is what you see above... The safe area inset's bottom is always 0 (regardless if the phone has a notch or not); so either the linked solution does not work any more or I have made a mistake. I am trying to figure out which and possibly find a solution to it.Terr
T
12

I had to dig around quite a bit but found the answer (I'd like to shout out to user6788419 whose right answer was berried deep in another thread).

First of all, the above code is correct. Checking if the safe area's bottom inset is larger than zero will accurately identify iPhones with a notch (as of this writing). So, this is correct:

if (@available( iOS 11.0, * )) {
    if ([[[UIApplication sharedApplication] keyWindow] safeAreaInsets].bottom > 0) {
        // iPhone with notch
    }
}

However, it matters where you put the above statement in your code because UIWindow is not available until the first run loop has concluded. That means, if you check the notch in your viewDidLoad or before it concluded (in your init for example), the bottom inset will always be zero.

If you, similarly to me, need this check to setup your main view, you can just move all your setup into separate function (such as postViewDidLoad) and call it once viewDidLoad has concluded:

[self performSelector:@selector(postViewDidLoad) withObject:nil afterDelay:0.0f];

Or, alternatively, you enclose it:

dispatch_async(dispatch_get_main_queue(), ^{
    // Check notch here
});

UPDATE: code for iOS 13 and up (does the same thing). "areaPosition" is a string argument when you call the function. "top" checks for the notch, everything else checks for the presence of the bottom home indicator.

- (UIWindow *) keyWindow {
    UIWindow *foundWindow   = nil;
    NSArray *windows        = [[UIApplication sharedApplication]windows];
    for (UIWindow *window in windows) {
        if (window.isKeyWindow) {
            foundWindow     = window;
            break;
        }
    }
    return foundWindow;
}

- (BOOL) checkSafeArea:(NSString *)areaPosition {
   if (@available(iOS 13.0, *)) {
       if ([areaPosition isEqualToString:@"top"]) {
           return [self keyWindow].safeAreaInsets.top > 20.0f;
       } else {
           return [self keyWindow].safeAreaInsets.bottom > 0.0f;
       }
   } else {
       if ([areaPosition isEqualToString:@"top"]) {
           return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0f;
       } else {
           return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom > 0.0f;
       }
   }
   return  NO;
}
Terr answered 20/4, 2019 at 16:8 Comment(3)
Hey Gergely, i get a deprecation warning for keywindow in IOS13, you wouldn't happen to know a way to do this to get around this?Asthenopia
Does not work with iPhone 13 Pro MaxTingle
I've added a more recent code that works on current devices.Terr
J
3

Updated for Swift 5 and iOS14

This solves the keyWindow deprecation warning.

var hasNotch: Bool {
       
 let bottom = UIApplication.shared.windows.first{ $0.isKeyWindow }?.safeAreaInsets.bottom ?? 0
 return bottom > 0
           
    }
Jarman answered 7/2, 2021 at 15:28 Comment(0)
T
3

Swift 5 and (iOS12 or Above)

var isNotch: Bool {
   return (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0) > 0
}
Toneme answered 8/2, 2021 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.