iOS: Detect if the device is iPhone X family (frameless)

19,480

Solution 1

You could "fitler" for the top notch, something like:

var hasTopNotch: Bool {
    if #available(iOS 11.0, tvOS 11.0, *) {
        return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
    }
    return false
}

Solution 2

Swift 5, iOS 14 supported

Thanks to @Tanin and @DominicMDev, since keyWindow was deprecated in iOS 13 and the iPad Pro has non-zero safeAreaInsets, this works fine for me.

(Already tested on iPhone 8, iPhone 11 Pro and iPad Pro (11-inch)(2nd gen) Simulators)

extension UIDevice {
    /// Returns `true` if the device has a notch
    var hasNotch: Bool {
        guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else { return false }
        if UIDevice.current.orientation.isPortrait {
            return window.safeAreaInsets.top >= 44
        } else {
            return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
        }
    }
}

Solution 3

Since keyWindow was deprecated in iOS 13, based on the solution to find keyWindow from here, this one works for me

extension UIDevice {
    var hasNotch: Bool {
        if #available(iOS 11.0, *) {
            let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
            return keyWindow?.safeAreaInsets.bottom ?? 0 > 0
        }
        return false
    }

}

Solution 4

This is valid for any orientation. No need to worry about iOS version before 11.0 since iPhone X minimum version is 11.0. Source

extension UIDevice {

    var hasNotch: Bool {
        if #available(iOS 11.0, *) {
           return UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0 > 0
        }
        return false
   }
}

Solution 5

I am doing it like this because the iPadPro has non-zero safeAreaInsets.

extension UIDevice {

    /// Returns 'true' if the device has a notch
    var hasNotch: Bool {
        guard #available(iOS 11.0, *), let window = UIApplication.shared.keyWindow else { return false }
        let orientation = UIApplication.shared.statusBarOrientation
        if orientation.isPortrait {
            return window.safeAreaInsets.top >= 44
        } else {
            return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
        }
    }

}
Share:
19,480
Mark cubn
Author by

Mark cubn

Updated on June 28, 2022

Comments

  • Mark cubn
    Mark cubn almost 2 years

    In my app there is some logic for frameless devices (iPhoneX, Xs Xs max, Xr). Currently it works base on the model of the devices, so, I detect the model by DeviceKit framework.

    But I want to extend this logic to future frameless devices. Probably in one year we will have some extra frameless devices. So, how can I detect if device is frameless or not? It should cover all current frameless devices and future one.

    We can not rely on faceID, safeAreaInset, screen height or size. So, then what?

  • MarekR
    MarekR almost 5 years
    That doesn't work for iPad Pro where statusBarHeight is 24pt
  • claude31
    claude31 over 4 years
    keyWindow is now deprecated.
  • Saafo
    Saafo over 3 years
    @NikhilMuskur I've tried on iPhone 8 Plus, iPhone 12 Pro and iPad Pro (11-inch) on iOS 14.1, Xcode 12.1 just now and it works well. What's your condition?
  • Nikhil Muskur
    Nikhil Muskur over 3 years
    Everything works correctly in the simulator but when I run this on a device the isPortrait property is always false
  • Saafo
    Saafo over 3 years
    @NikhilMuskur can you give a more precise description about your situation? On what device and how do you specified the isPortrait property is always false?
  • Nikhil Muskur
    Nikhil Muskur over 3 years
    While debugging I found that UIDevice.current.orientation.isPortrait always returned false and window.safeAreaInsets.left was equal to 0. I tested this on iPhone 11. Strangely the condition is working correctly on the simulator
  • Saafo
    Saafo over 3 years
    @NikhilMuskur Well I've tested on my iPhone X and UIDevice.current.orientation.isPortrait works well ( return true when portrait )...
  • David
    David over 3 years
    Can confirm, not working, for the rootViewController of UIVindow, later on - it works
  • zhisme
    zhisme over 3 years
    it is a good practice to advocate your code, consider adding some description to your answer
  • Haseeb Javed
    Haseeb Javed about 3 years
    MarekR -> try ".bottom instead of .top"
  • fishinear
    fishinear about 3 years
    Also describe how your answer differs from the 8 existing answers.
  • idris yıldız
    idris yıldız over 2 years
  • Vladimir Amiorkov
    Vladimir Amiorkov over 2 years
    This breaks on iPad 11 inch 3 generation, because that device has a keyWindow?.safeAreaInsets.bottom == 20 because it does not have a bottom button. The answer from "Saafo" is what I used in the end.
  • StackUnderflow
    StackUnderflow almost 2 years
    "fitler" ??? Did you mean "filter" ?