webdevqa.jp.net

デバイスがiPhone Xかどうかを検出

私のiOSアプリはUINavigationBarにカスタムの高さを使用しているため、新しいiPhone Xではいくつかの問題が発生します。

アプリがiPhone X上で実行されている場合、/ Objective-Cで信頼できるをプログラムで検出する方法を既に知っていますか。

EDIT:

もちろん、画面のサイズをチェックすることは可能ですが、iOSを検出するためのTARGET_OS_IPHONEのような「組み込み」メソッドがあるのでしょうか。

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    if (screenSize.height == 812)
        NSLog(@"iPhone X");
}

編集2:

私の質問がリンクされた質問の複製であるとは思わない。もちろん、現在のデバイスのさまざまな特性を「測定」し、その結果を使用してどのデバイスを使用するかを決定する方法があります。しかし、私が最初の編集で強調しようとしたので、これは私の質問の実際のポイントではありませんでした。

"現在のデバイスがiPhone Xであるかどうかを直接検出することは可能ですか(例えば、SDKの機能によって)、間接測定を使用する必要がありますか?

これまでの答えでは、答えは「いいえ、直接的な方法はありません。測定は進むべき道です」と考えています。

234
Andrei Herford

あなたの質問に基づいて、答えはノーです。直接的な方法はありません。より多くの情報のためにあなたはここで情報を得ることができます:

そして

IPhone Xの高さは2436 pxです

デバイスの画面サイズと解像度 から::

enter image description here

デバイスの画面サイズと向き :から:

enter image description here

Swift 3以降

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")

        case 2688:
            print("iPhone XS Max")

        case 1792:
            print("iPhone XR")

        default:
            print("Unknown")
        }
    }

目的語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, 2208:
            printf("iPhone 6+/6S+/7+/8+");
            break;

        case 2436:
            printf("iPhone X, XS");
            break;

        case 2688:
            printf("iPhone XS Max");
            break;

        case 1792:
            printf("iPhone XR");
            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");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
        Console.WriteLine("iPhone XS Max");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
        Console.WriteLine("iPhone XR");
    } else {
        Console.WriteLine("Unknown");
    }
}

次のようにあなたの質問に基づいて:

あるいはscreenSize.heightをint 812.0fではなくfloat 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");
    }

詳細については、iOSヒューマンインタフェースガイドラインの次のページを参照してください。

スイフト

topNotchで検出します。

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

    return false
}

目的語C

- (BOOL)hasTopNotch {
    if (@available(iOS 11.0, *)) {
        return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
    }

    return  NO;
}

_ update _

userInterfaceIdiomのドキュメント で説明されているように、デバイスタイプの識別にuserInterfaceIdiomプロパティを使用しないでください。

ユニバーサルアプリケーションの場合は、このプロパティを使用して、特定の種類のデバイスに合わせてアプリケーションの動作を調整できます。たとえば、iPhoneとiPadのデバイスでは画面サイズが異なるため、現在のデバイスの種類に基づいて異なるビューとコントロールを作成することをお勧めします。

つまり、このプロパティは実行中のアプリの表示スタイルを識別するためだけに使用されます。ただし、iPhoneアプリケーション(ユニバーサルではない)は、App storeを介してiPadデバイスにインストールできます。その場合、userInterfaceIdiomUIUserInterfaceIdiomPhoneも返します。

正しい方法はunameでマシン名を取得することです。詳細については、以下を確認してください。

306
Anbu.Karthik

もう1つの可能性。iOS11とiOS 12で動作するのは、iPhone Xが一番上にノッチと44のインセットを持つ唯一のものだからです。

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
}

もちろん、横向きの場合は、左右の安全領域の差し込みを確認する必要があります。

編集:_windowはAppDelegateのUIWindowです。このチェックはアプリケーションのdidFinishLaunchingWithOptionsで行われます。

iOS 12用に更新され、top> 0ではなくtop> 24かどうかがチェックされます

編集:シミュレータでは、ハードウェア、着信ステータスバーの切り替えに行くことができます。こうすることで、通話中にiOS 11のiPhone XまたはiPhone XS iOS 12のステータスバーの高さが変わらないことがわかります。どちらも変化するのは時間アイコンで、どちらも緑色の背景色になります。これが簡単です。

enter image description here

92
saswanb

あなたは実際の必要性に応じてiPhone Xの異なる検出を実行するものとします。

トップノッチ(ステータスバー、ナビゲーションバー)などを扱うため.

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
}

一番下のホームインジケーター(タブバー)などを扱うため.

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
}

背景サイズ、フルスクリーン機能など.

class var isIphoneXOrBigger: Bool {
    // 812.0 on iPhone X, XS.
    // 896.0 on iPhone XS Max, XR.
    return UIScreen.main.bounds.height >= 812
}

注:最終的にUIDevice.current.userInterfaceIdiom == .phoneと混在させる
注:この方法ではLaunchScreenストーリーボードまたは適切なLaunchImagesが必要です。

背景の比率、スクロール機能など.

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
}

注:この方法では、LaunchScreenストーリーボードまたは適切なLaunchImagesが必要です。

分析、統計、追跡など.

マシンIDを取得して、それを文書化された値と比較します。

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"
}

アナリティクスに有効なiPhone Xとしてシミュレータを含めるには:

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"
}

IPhone XS、XS Max、およびXRを含めるには、単に「iPhone 11」で始まるモデルを探します。

return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")

faceIDサポート用

import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
    if #available(iOS 11.0, *) {
        return LAContext().biometryType == .typeFaceID
    }
    return false
}
52
Cœur

あなたは次元に従って iPhone X deviceを検出するためにこのようにすることができます。

速い ​​

if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
   //iPhone X
}

目的 - C

if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436)  {
  //iPhone X     
}

enter image description here

しかし

これは十分な方法ではありません。もしAppleがiPhone Xと同じ大きさの次のiPhoneを発表したらどうなるでしょう。ですから最良の方法はハードウェア文字列を使ってデバイスを検出することです。

新しいデバイスのハードウェア文字列は以下の通りです。

iPhone 8 - iPhone 10,1 または iPhone 10,4

iPhone 8 Plus - iPhone10,2 または iPhone 10,5

iPhone X - iPhone 10,3 または iPhone 10,6

41
Jaydeep

デバイスモデル/マシン名 を調べてください。コード内のポイント/ピクセル数を直接使用しないでください。これは hard code であり、デバイスハードウェアには意味がありません。

#import <sys/utsname.h>

NSString* deviceName()
{
    struct utsname systemInfo;
    uname(&systemInfo);

    return [NSString stringWithCString:systemInfo.machine
                          encoding:NSUTF8StringEncoding];
}

結果:

@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)

この回答 を参照してください。

フルコード実装:

#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)
{
    NSString *strModelID = GetDeviceModel();

    return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"] || // iPhone X
           [strModelID isEqualToString:@"iPhone11,2"] || [strModelID isEqualToString:@"iPhone11,4"] || [strModelID isEqualToString:@"iPhone11,6"] || // iPhone XS (Max)
           [strModelID isEqualToString:@"iPhone11,8"]; // iPhone XR
}
36
Itachi
#define IS_IPHONE        (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 480.0)
#define IS_IPHONE_5      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
#define IS_IPHONE_6      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
#define IS_IPHONE_6PLUS  (IS_IPHONE && [[UIScreen mainScreen] nativeScale] == 3.0f)
#define IS_IPHONE_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_IPHONE_X      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)

iS_IPHONE_Xを定義します(IS_IPHONE && [[UIScreen mainScreen] bounds] .size.height == 812.0)

#define IS_IPHONE_XS      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
#define IS_IPHONE_X_MAX      (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 896.0)
#define IS_RETINA        ([[UIScreen mainScreen] scale] >= 2.0) // 3.0 for iPhone X, 2.0 for others

#define IS_IPAD_DEVICE   [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]

注: - 注意してください、それは縦向きの場合にのみ正常に動作します

25
Jagveer Singh

すべての答えを見た後、これは私がやってしまったものです:

解決策(Swift 4.1互換)

extension UIDevice {
    static var isIphoneX: Bool {
        var modelIdentifier = ""
        if isSimulator {
            modelIdentifier = 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)
            modelIdentifier = String(cString: machine)
        }

        return modelIdentifier == "iPhone10,3" || modelIdentifier == "iPhone10,6"
    }

    static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0
    }
}

つかいます

if UIDevice.isIphoneX {
    // is iPhoneX
} else {
    // is not iPhoneX
}

注意

Pre Swift 4.1では、アプリがシミュレータ上で動作しているかどうかを確認できます。

TARGET_OS_SIMULATOR != 0

Swift 4.1以降では、 ターゲット環境のプラットフォーム状態を使用して、アプリがシミュレータ上で実行されているかどうかを確認できます

#if targetEnvironment(simulator)
    return true
#else
    return false
#endif

(古い方法でもまだ動作しますが、この新しい方法は将来的にはさらに有効です)

23
Cloud9999Strife

寸法に基づいたこれらの回答はすべて、将来のデバイスでの不正な動作の影響を受けやすくなります。今日は動作しますが、来年は同じサイズで、ガラスの下にカメラなどがあり、「ノッチ」がないiPhoneがある場合はどうでしょうか。唯一のオプションがアプリを更新することである場合、それはあなたとあなたの顧客にとって貧弱なソリューションです。

「iPhone10,1」などのハードウェアモデル文字列を確認することもできますが、Appleが世界中のさまざまなキャリアに対して異なるモデル番号をリリースすることがあるため、問題があります。

正しいアプローチは、トップレイアウトを再設計するか、カスタムナビゲーションバーの高さに関する問題を解決することです(これに焦点を合わせます)。ただし、これらのいずれも行わないことにした場合は、何をしていても、これを機能させるためのハックであることを理解してくださいtoday、そしてハックを機能させ続けるために、ある時点で(おそらく複数回)修正する必要があります。

18
clarus

Swift 4+回答

iPhone X、XR、XS、XSMAX:

注:テストには実際のデバイスが必要です

参照

 let deviceType = UIDevice.current.modelName
        switch deviceType {
        case "iPhone10,3", "iPhone10,6":
            print("iPhoneX")
        case "iPhone11,2":
            print("iPhone XS")
        case "iPhone11,4":
            print("iPhone XS Max")
        case "iPhone11,6":
            print("iPhone XS Max China")
        case "iPhone11,8":
            print("iPhone XR")
        default:
            break
}

extension UIDevice {
    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        return identifier
    }
}
10
Jack

はい、可能です。 UIDevice-Hardware拡張機能 をダウンロードして(またはCocoaPodの 'UIDevice-Hardware'を使ってインストールして)次のコマンドを使います

NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];

これはシミュレータでは機能せず、実際のデバイスでのみ機能することに注意してください。

10
Hendrik

私はそれが Swift だけの解決策であることを知っています、しかしそれは誰かを助けることができます。

私はすべてのプロジェクトでglobals.Swiftを持っています、そして私がいつも追加するものの1つはユーザーのデバイスを簡単に検出するためのDeviceTypeです:

struct ScreenSize {
  static let width = UIScreen.main.bounds.size.width
  static let height = UIScreen.main.bounds.size.height
  static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
  static let maxWH = max(ScreenSize.width, ScreenSize.height)
}

struct DeviceType {
  static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH < 568.0
  static let iPhone5orSE   = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 568.0
  static let iPhone678     = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 667.0
  static let iPhone678p    = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 736.0
  static let iPhoneX       = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 812.0
  static let iPhoneXRMax   = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 896.0
  static var hasNotch: Bool {
    return iPhoneX || iPhoneXRMax
  }
}

それを使用するには:

if DeviceType.hasNotch {
  print("This executes on all phones with a notch")
}

if DeviceType.iPhone678 {
  print("This executes on iPhones 6, 7 and 8")
}

プロジェクトでLaunchImageを使用する場合、UIScreen.main.boundsはそれらがないと適切な値を返さないため、サポートされているすべてのデバイス(XS Max、XRなど)にイメージを追加してください。

7
budidino

Swift 4 再利用可能 拡張子

    public extension UIDevice {

    public enum `Type` {
        case iPad
        case iPhone_unknown
        case iPhone_5_5S_5C
        case iPhone_6_6S_7_8
        case iPhone_6_6S_7_8_PLUS
        case iPhone_X_Xs
        case iPhone_Xs_Max
        case iPhone_Xr
    }

    public var hasHomeButton: Bool {
        switch type {
        case .iPhone_X_Xs, .iPhone_Xr, .iPhone_Xs_Max:
            return false
        default:
            return true
        }
    }

    public var type: Type {
        if userInterfaceIdiom == .phone {
            switch UIScreen.main.nativeBounds.height {
            case 1136:
                return .iPhone_5_5S_5C
            case 1334:
                return .iPhone_6_6S_7_8
            case 1920, 2208:
                return .iPhone_6_6S_7_8_PLUS
            case 2436:
                return .iPhone_X_Xs
            case 2688:
                return .iPhone_Xs_Max
            case 1792:
                return .iPhone_Xr
            default:
                return .iPhone_unknown
            }
        }
        return .iPad
   }
}
6
ale_stro

@ saswanbの回答によると、これはSwift 4バージョンです。

var iphoneX = false
if #available(iOS 11.0, *) {
    if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
        iphoneX = true
    }
}
6
MattOZ

heightを使用しているすべての答えは、1つの理由でストーリーの半分に過ぎません。デバイスの向きがlandscapeLeftまたはlandscapeRightのときにそのようにチェックしようとすると、heightwidthと入れ替えられるため、チェックは失敗します。

Swift 4.0で私の解決策がこんな風に見えるのはそのためです。

extension UIScreen {
    ///
    static var isPhoneX: Bool {
        let screenSize = UIScreen.main.bounds.size
        let width = screenSize.width
        let height = screenSize.height
        return min(width, height) == 375 && max(width, height) == 812
    }
}
5
DevAndArtist

AppleがUINavigationBarの高さを変えてリリースした唯一のデバイスがiPhone Xになるとは限りません。より一般的な解決策を使用してこの問題を解決してみてください。バーを常にデフォルトの高さより20ピクセル大きくしたい場合は、コードを64ピクセル(44ピクセル+ 20ピクセル)に設定するのではなく、バーの高さに20ピクセルを追加する必要があります。

4
IMcD23

スイフト3 + 4:

任意のデバイスサイズのピクセル値を必要とせず

//UIApplication+SafeArea.Swift

extension UIApplication { 

    static var isDeviceWithSafeArea:Bool {

        if #available(iOS 11.0, *) {
            if let topPadding = shared.keyWindow?.safeAreaInsets.bottom,
                topPadding > 0 {
                return true
            }
        }

        return false
    }
}

例:

if UIApplication.isDeviceWithSafeArea {
     //e.g. change the frame size height of your UITabBar
}
4
Peter Kreinz
struct ScreenSize {
    static let width = UIScreen.main.bounds.size.width
    static let height = UIScreen.main.bounds.size.height
    static let maxLength = max(ScreenSize.width, ScreenSize.height)
    static let minLength = min(ScreenSize.width, ScreenSize.height)
    static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
}

struct DeviceType {
    static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength < 568.0
    static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 568.0
    static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 667.0
    static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 736.0
    static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 812.0

    static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1024.0
    static let IS_IPAD_PRO          = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1366.0
}
4
Kiran Sarvaiya

他のソリューションで提案されているように、画面のピクセルサイズを使用しないでください。これは、将来のデバイスで誤検知が発生する可能性があるため、不適切です。 UIWindowがまだレンダリングされていない場合(AppDelegate)、ランドスケープアプリでは機能せず、スケールが設定されている場合はシミュレーターで失敗する可能性があります。

代わりに、この目的のためにマクロを作成しました。非常に使いやすく、前述の問題を防ぐためにハードウェアフラグに依存しています。

編集:iPhoneX、iPhone XS、iPhoneXR、iPhoneXS Maxをサポートするように更新


使用するには:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

うん、本当に。


マクロ:

これを任意の場所にコピーして貼り付けます。@endの後の.hファイルの一番下を好みます

#import <sys/utsname.h>

#if TARGET_IPHONE_SIMULATOR
#define IS_SIMULATOR YES
#else
#define IS_SIMULATOR NO
#endif

#define IS_DEVICE_IPHONEX (\
(^BOOL (void){\
NSString *__modelIdentifier;\
if (IS_SIMULATOR) {\
__modelIdentifier = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];\
} else {\
struct utsname __systemInfo;\
uname(&__systemInfo);\
__modelIdentifier = [NSString stringWithCString:__systemInfo.machine encoding:NSUTF8StringEncoding];\
}\
NSString *__iPhoneX_GSM_Identifier = @"iPhone10,6";\
NSString *__iPhoneX_CDMA_Identifier = @"iPhone10,3";\
NSString *__iPhoneXR_Identifier = @"iPhone11,8";\
NSString *__iPhoneXS_Identifier = @"iPhone11,2";\
NSString *__iPhoneXSMax_China_Identifier = @"iPhone11,6";\
NSString *__iPhoneXSMax_Other_Identifier = @"iPhone11,4";\
return ([__modelIdentifier isEqualToString:__iPhoneX_GSM_Identifier] || [__modelIdentifier isEqualToString:__iPhoneX_CDMA_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXR_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXS_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_China_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_Other_Identifier]);\
})()\
)
3
Albert Renshaw
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
3
alexander.pan

通常、プログラマーは上または下に制限するためにそれを必要とします。

static func extraTop() -> CGFloat {

    var top: CGFloat = 0

    if #available(iOS 11.0, *) {

        if let t = UIApplication.shared.keyWindow?.safeAreaInsets.top {
            top = t
        }
    }
    return top
}

static func extraBottom() -> CGFloat {

    var bottom: CGFloat = 0

    if #available(iOS 11.0, *) {

        if let b = UIApplication.shared.keyWindow?.safeAreaInsets.bottom {
            bottom = b
        }
    }
    return bottom
}

IPhone Xより前の場合、これらのメソッドは以下を返します。0

IPhone Xの場合:44と34はそれに応じて

それからこれらの追加を上または下の制約に追加するだけです。

3
Andrey

ネイティブ境界の高さが(私のように)2436pxではなく2001pxになっているのは、iOS 11(Xcode 9ではなくXcode 8)より前の古いSDKを使ってアプリを構築したためです。古いSDKを使用すると、iOSは、画面の端から端まで、最上位の「センサーノッチ」を超えて拡張するのではなく、iPhone X上で「ブラックボックス化」されたアプリを表示します。これにより、画面サイズが縮小されるため、このプロパティは2436ではなく2001を返します。

最も簡単な解決策は、デバイスの検出だけに関心がある場合は、両方のサイズをチェックすることです。バイオメトリックタイプを指定するENUM値を持たない古いXcode SDKを使用して構築しながら、FaceIDを検出するためにこの方法を使用しました。このような状況では、画面の高さを使用したデバイス検出は、Xcodeを更新しなくても、デバイスにFaceIDとTouchIDがあるかどうかを知るための最良の方法のように見えました。

3
Jon Summers
- (BOOL)isIphoneX {
    if (@available(iOS 11.0, *)) {
        UIWindow *window = UIApplication.sharedApplication.keyWindow;
        CGFloat topPadding = window.safeAreaInsets.top;
        if(topPadding>0) {
            return YES;
        }
        else {
            return NO;
        }
    }
    else {
        return NO;
    }
}
3
user6788419

私はあなたの他の答えについて詳しく述べ、UIDeviceのSwift拡張を作りました。私はSwift列挙型と「順不同」と噴霧化が好きです。私は、デバイスとシミュレータの両方で機能するソリューションを作成しました。 

利点: - シンプルなインターフェース、使い方UIDevice.current.isIPhoneX - UIDeviceModelType enumを使用すると、アプリで使用するモデル固有の機能や定数を簡単に拡張できます。 cornerRadius

デメリット: - 解像度固有ではなく、モデル固有のソリューションです。 Appleが同じスペックで別のモデルを作成する場合、これは正しく機能しません。この機能を実現するには別のモデルを追加する必要があります。

extension UIDevice {

    enum UIDeviceModelType : Equatable {

        ///iPhoneX
        case iPhoneX

        ///Other models
        case other(model: String)

        static func type(from model: String) -> UIDeviceModelType {
            switch model {
            case "iPhone10,3", "iPhone10,6":
                return .iPhoneX
            default:
                return .other(model: model)
            }
        }

        static func ==(lhs: UIDeviceModelType, rhs: UIDeviceModelType) -> Bool {
            switch (lhs, rhs) {
            case (.iPhoneX, .iPhoneX):
                return true
            case (.other(let modelOne), .other(let modelTwo)):
                return modelOne == modelTwo
            default:
                return false
            }
        }
    }

    var simulatorModel: String? {
        guard TARGET_OS_SIMULATOR != 0 else {
            return nil
        }

        return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"]
    }

    var hardwareModel: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let model = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        return model
    }

    var modelType: UIDeviceModelType {
        let model = self.simulatorModel ?? self.hardwareModel
        return UIDeviceModelType.type(from: model)
    }

    var isIPhoneX: Bool {
        return modelType == .iPhoneX
    }
}
2
deathhorse

私はそれがiPhone Xであるかどうかを検出するためにステータスバーフレームの高さに頼る:

if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
    // It is an iPhone X
}

これはアプリケーションの肖像画のためです。デバイスの向きに応じてサイズを確認することもできます。また、他のiPhoneでは、ステータスバーが隠れている可能性があるので、フレームの高さは0です。 iPhone Xでは、ステータスバーは非表示になりません。

2
Tiois

Peter Kreinzのコード (きれいで、必要なことをしたため)を使用していましたが、その後、デバイスが縦向きになったときに機能することに気付きました(明らかに上部パディングが上部になるので)それで、私はスクリーンサイズに頼ることなく、それぞれのパディングですべての方向を扱うための拡張を作成しました:

extension UIDevice {

    var isIphoneX: Bool {
        if #available(iOS 11.0, *), isIphone {
            if isLandscape {
                if let leftPadding = UIApplication.shared.keyWindow?.safeAreaInsets.left, leftPadding > 0 {
                    return true
                }
                if let rightPadding = UIApplication.shared.keyWindow?.safeAreaInsets.right, rightPadding > 0 {
                    return true
                }
            } else {
                if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 0 {
                    return true
                }
                if let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom, bottomPadding > 0 {
                    return true
                }
            }
        }
        return false
    }

    var isLandscape: Bool {
        return UIDeviceOrientationIsLandscape(orientation) || UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation)
    }

    var isPortrait: Bool {
        return UIDeviceOrientationIsPortrait(orientation) || UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
    }

    var isIphone: Bool {
        return self.userInterfaceIdiom == .phone
    }

    var isIpad: Bool {
        return self.userInterfaceIdiom == .pad
    }
}

そしてあなたの電話サイトであなたはただ:

let res = UIDevice.current.isIphoneX
2
rgkobashi

あるいは、 ' DeviceKit 'ポッドをチェックすることもできます。

import DeviceKit
let device = Device()
if device == .iPhoneX {
  // place your code here
}
1

私は最近同じ問題を解決しなければなりませんでした。そして、この質問に対する最終的な答え(「いいえ」)はありますが、これはiPhone X特有のレイアウトの振る舞いを必要とする他の人々を助けるかもしれません。 

デバイスがiPhone Xであるかどうかにはあまり興味がありませんでした。デバイスにノッチ付きディスプレイがあるかどうかには興味がありませんでした。

private static var hasNotchedDisplay: Bool {
    if let window = UIApplication.shared.keyWindow {
        return (window.compatibleSafeAreaInsets.top > 20.0 || window.compatibleSafeAreaInsets.left > 0.0 || window.compatibleSafeAreaInsets.right > 0.0)
    }

    return false
}

同じ行に沿ってhasOnScreenHomeIndicator変数を書くこともできます(ただし、一番下の安全領域を確認してください)。

上記はiOS 10以前のセーフエリアインセットへの便利なアクセスのためにUIViewの私の拡張子を使います。 

@objc public extension UIView {
    @objc public var compatibleSafeAreaInsets: UIEdgeInsets {
        if #available(iOS 11.0, *) {
            return safeAreaInsets
        } else {
            return .zero
        }
    }

    @objc public var compatibleSafeAreaLayoutGuide: UILayoutGuide {
        if #available(iOS 11.0, *) {
            return safeAreaLayoutGuide
        } else {
            return layoutMarginsGuide
        }
    }
}
1
simeon

デバイスが何かを知りたい理由がいくつかあります。

  1. あなたは、デバイスの高さ(と幅)を確認することができます。これはレイアウトには便利ですが、正確なデバイスを知りたい場合は通常そうしたくありません。

  2. レイアウトの目的で、UIView.safeAreaInsetsを使うこともできます。

  3. たとえば、診断目的で電子メールに含めるためにデバイス名を表示したい場合は、sysctl ()を使用してデバイスモデルを取得した後、これと同等のものを使用して名前を計算できます。

    $ curl http://appledevicenames.com/devices/iPhone10,6
    
    iPhone X
    
0
Hwee-Boon Yar

Appleは、デバイスに「ノッチ」または「ホームインジケータ」があるかどうかを手動で確認したくない しかし動作するコードは次のとおりです。

-(BOOL)hasTopNotch{

    if (@available(iOS 11.0, *)) {

        float max_safe_area_inset = MAX(MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right),MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left));

        return max_safe_area_inset >= 44.0;

    }

    return  NO;

}

-(BOOL)hasHomeIndicator{

    if (@available(iOS 11.0, *)) {

        int iNumberSafeInsetsEqualZero = 0;

        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom == 0.0)iNumberSafeInsetsEqualZero++;
        if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left == 0.0)iNumberSafeInsetsEqualZero++;

        return iNumberSafeInsetsEqualZero <= 2;

    }

    return  NO;

}

他の投稿の一部は機能しません。たとえば、縦向きモードで「通話中ステータスバー」(緑色のバー)が付いているiPhone 6Sには、一番上の安全な差し込みがあります。私のコードでは、すべてのケースが取り上げられています( デバイスが縦向きまたは横向きで起動している場合でも

0
BIOS-K

デバイスがiPhone Xであるかどうかを検出するための最善かつ最も簡単な方法は、

https://github.com/stephanheilner/UIDevice-DisplayName

var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier}
            return identifier + String(UnicodeScalar(UInt8(value)))}

また、iPhone Xの場合、識別子は "iPhone 10,3"または "iPhone 10,6" のいずれかです。

0
satheeshwaran

Portrait onlyでは、ビューのフレームの幅と高さを使ってチェックします。

override func viewDidLoad() {
    super.viewDidLoad()

    // iPhone Xr: -414 x 896
    // iPhone Xs Max: -414 x 896
    // iPhone X, Xs: -375 x 812

    if view.frame.width == 414 && view.frame.height == 896 || view.frame.width == 375 && view.frame.height == 812  {

        print("iPhone X")
    } else {

        print("not iPhone X")
    }

}

縦型スクリーンの寸法は以下のとおりです

enter image description here

0
Lance Samaria

IOS 12のリリースで、iPhone Xのようなデバイスがこのカテゴリに入るかもしれません。 

extension UIDevice {
    var isPortrait: Bool {

       return UIDeviceOrientationIsPortrait(orientation) ||
      UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)

  }

   var isDeviceWith_XShape : Bool {

    if self.userInterfaceIdiom == .phone {

        if isPortrait
        {
            switch UIScreen.main.nativeBounds.height {

            case 2436,2688,1792:
                print("iPhone X, Xs, Xr, Xs Max")
                return true
            default:
                print("Any other device")
                return false
            }
        }
        else
        {
            switch UIScreen.main.nativeBounds.width {

            case 2436,2688,1792:
                print("iPhone X, Xs, Xr, Xs Max")
                return true
            default:
                print("Any other device")
                return false
            }
        }


    }
    else
    {
        return false
    }

}`
0
dev_shanghai

迅速な修正のために、私はこれが好きです:

let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>
0
Andres Canella

簡単な方法でデバイスを検出する。以下のように、

func isPhoneDevice() -> Bool {
    return UIDevice.current.userInterfaceIdiom == .phone
}

func isDeviceIPad() -> Bool {
    return UIDevice.current.userInterfaceIdiom == .pad
}

func isPadProDevice() -> Bool {
    let SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width
    let SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .pad && SCREEN_MAX_LENGTH == 1366.0
}

func isPhoneXandXSDevice() -> Bool {
    let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
    let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 812.0
}

func isPhoneXSMaxandXRDevice() -> Bool {
    let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
    let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
    let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)

    return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 896.0
}

そしてこう呼んで

if isPhoneDevice() {
     // Your code
}
0
User558