Ermitteln Sie, ob es sich bei dem Gerät um ein iPhone X handelt

262

Meine iOS-App verwendet eine benutzerdefinierte Höhe für die, UINavigationBarwas zu einigen Problemen auf dem neuen iPhone X führt.

Weiß jemand bereits, wie man programmgesteuert (in Objective-C) zuverlässig erkennt, ob eine App auf dem iPhone X ausgeführt wird?

BEARBEITEN:

Natürlich ist es möglich, die Größe des Bildschirms zu überprüfen. Ich frage mich jedoch, ob es eine "eingebaute" Methode gibt TARGET_OS_IPHONE, mit der iOS erkannt werden kann ...

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

EDIT 2:

Ich glaube nicht, dass meine Frage ein Duplikat der verknüpften Frage ist. Natürlich gibt es Methoden, um verschiedene Eigenschaften des aktuellen Geräts zu "messen" und anhand der Ergebnisse zu entscheiden, welches Gerät verwendet wird. Dies war jedoch nicht der eigentliche Punkt meiner Frage, wie ich in meiner ersten Bearbeitung zu betonen versuchte.

Die eigentliche Frage lautet: "Kann direkt erkannt werden, ob es sich bei dem aktuellen Gerät um ein iPhone X handelt (z. B. durch eine SDK-Funktion), oder muss ich indirekte Messungen durchführen ? "

Bei den bisher gegebenen Antworten gehe ich davon aus, dass die Antwort "Nein, es gibt keine direkten Methoden. Messungen sind der richtige Weg" lautet.

Andrei Herford
quelle
Das iPhone X hat eine andere Bildschirmauflösung als andere.
El Tomato
2
Ja, wie ich in meiner Bearbeitung erwähnt habe, ist es möglich, die Bildschirmgröße zu überprüfen. Die Frage ist jedoch, ob es eine "direkte" Methode gibt, um den Gerätetyp abzufragen, anstatt "indirekte" Messungen ...
Andrei Herford
3
Der Autor möchte nur den Gerätetyp erhalten, nicht die Bildschirmauflösung. Warum nicht den Maschinennamen direkt überprüfen? @ Lubilis ist richtig.
Itachi
2
Warum verwenden Sie nicht einfach die von Apple empfohlenen Sicherheitsbereich-Anleitungen?
Holex
4
WICHTIG, zukünftige Entwickler: Erkennen Sie dies nicht anhand der Bildschirmhöhe, wie aktuelle Top-Lösungen vermuten lassen. Es ist schlecht, da dies zu Fehlalarmen für zukünftige Geräte führen kann. funktioniert nicht, wenn UIWindow noch nicht gerendert wurde (wie in Ihren AppDelegate-Init-Funktionen), funktioniert nicht in Landschafts-Apps und kann im Simulator fehlschlagen, wenn die Skalierung festgelegt ist. Verwenden Sie für solche Dinge NIEMALS magische Zahlen! Sie können Hardware-Flags überprüfen, um den Erfolg zu garantieren, wie ich es hier getan habe: stackoverflow.com/a/51511947/2057171
Albert Renshaw

Antworten:

383

Basierend auf Ihrer Frage lautet die Antwort nein. Es gibt keine direkten Methoden. Für weitere Informationen erhalten Sie die Informationen hier:

und

Die Höhe des iPhone X beträgt 2436 px

Vom Gerätebildschirm Größen und Auflösungen :

Geben Sie hier die Bildbeschreibung ein

Von Gerätebildschirmgrößen und -ausrichtungen :

Geben Sie hier die Bildbeschreibung ein

Swift 3 und höher :

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

Ziel-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:
            print("iPhone X/XS/11 Pro");
             break;

        case 2688:
            print("iPhone XS Max/11 Pro Max");
             break;

        case 1792:
            print("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");
    }
}

Basierend auf Ihrer Frage wie folgt:

Oder screenSize.heightals float 812.0f nicht int verwenden 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");
    }

Weitere Informationen finden Sie auf der folgenden Seite in den Richtlinien für die Benutzeroberfläche von iOS:

Schnell :

Erkennen mit topNotch:

Wenn jemand in Betracht zieht, das iPhoneX mit Notch zu erkennen, beachten Sie, dass es im Querformat für alle iPhones gleich ist.

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
}

Ziel-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 :

Verwenden Sie die userInterfaceIdiomEigenschaft nicht, um den Gerätetyp zu identifizieren, wie in der Dokumentation zu userInterfaceIdiom erläutert:

Für universelle Anwendungen können Sie diese Eigenschaft verwenden, um das Verhalten Ihrer Anwendung für einen bestimmten Gerätetyp anzupassen. Beispielsweise haben iPhone- und iPad-Geräte unterschiedliche Bildschirmgrößen. Daher möchten Sie möglicherweise je nach Typ des aktuellen Geräts unterschiedliche Ansichten und Steuerelemente erstellen.

Das heißt, diese Eigenschaft wird nur verwendet, um den Ansichtsstil der laufenden App zu identifizieren. Die iPhone-App (nicht die universelle) kann jedoch über den App Store auf dem iPad-Gerät installiert werden. In diesem Fall wird die App userInterfaceIdiomzurückgegebenUIUserInterfaceIdiomPhone auch.

Der richtige Weg ist, den Maschinennamen über zu erhalten uname. Überprüfen Sie Folgendes für Details:

Anbu.Karthik
quelle
Die Auflösung des iPhone X beträgt 2436 x 1125 Pixel gemäß: iphonesoft.fr/2017/09/12/…
Medhi
1
@Medhi - die Auflösung von iPhone X ist - 1125 x 2436 Pixel (~ 458 ppi Pixeldichte)
Anbu.Karthik
14
NEIN! Die iPhone-App (nicht das Universum) kann über den App Store auf dem iPad-Gerät installiert werden. In diesem Fall wird auch dieuserInterfaceIdiomzurückgegebenUIUserInterfaceIdiomPhone. Diese Antwort ist falsch.
Itachi
1
@ThreeCoins, bitte aktualisieren Sie Ihre Antwort für Plus-Geräte gemäß dem Vorschlag von Leo Dabus. Es funktioniert auf dem Plus-Simulator, aber nicht auf dem Gerät.
Hiren Gujarati
2
Dies ist schlecht, da dies zu Fehlalarmen für zukünftige Geräte führen kann. funktioniert nicht, wenn UIWindow noch nicht gerendert wurde (AppDelegate), funktioniert nicht in Landschafts-Apps und kann im Simulator fehlschlagen, wenn die Skalierung festgelegt ist. Sie können Hardware-Flags überprüfen, um den Erfolg zu garantieren, wie ich es hier getan habe: stackoverflow.com/a/51511947/2057171
Albert Renshaw
101

Eine weitere Möglichkeit, die unter iOS 11 und iOS 12 funktioniert, da das iPhone X das einzige mit einer Kerbe oben und einem Einschub von 44 ist. Das ist es, was ich hier wirklich erkenne:

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

Und natürlich müssen Sie möglicherweise die linken und rechten Sicherheitsbereiche überprüfen, wenn Sie sich im Querformat befinden.

Bearbeiten: _window ist das UIWindow des AppDelegate, in dem diese Prüfung in der Anwendung didFinishLaunchingWithOptions durchgeführt wird.

Die Antwort wurde für iOS 12 aktualisiert, um zu überprüfen, ob top> 24 statt top> 0 ist.

Bearbeiten: Im Simulator können Sie zu Hardware wechseln und die Statusleiste für eingehende Anrufe umschalten. Dies zeigt mir, dass sich die Höhe der Statusleiste auf dem iPhone X unter iOS 11 oder dem iPhone XS iOS 12 nicht ändert, wenn ein Anruf getätigt wird. Alles, was sich ändert, ist das Zeitsymbol, das in beiden Fällen einen grünen Hintergrund erhält. Hier ist ein Schnappschuss:

Geben Sie hier die Bildbeschreibung ein

saswanb
quelle
5
Die Einfügungen im sicheren Bereich enthalten die Höhe der Statusleiste (falls sichtbar) auf anderen Geräten. Wenn Sie
überprüfen,
3
"Dies kann in iPhone Xs oder iPhone 11 brechen ", sagte Cook.
Itachi
11
Ich habe ein wenig angepasst und verwendet if _window.safeAreaInsets != UIEdgeInsets.zero, um jede Geräteorientierung zu ermöglichen
Fraser
2
Wenn Sie nicht verwenden möchten .top, safeAreaInsets.bottomwird 34 auf dem iPhone X und 0 auf anderen Geräten sein
blwinters
7
Warnung: Verwenden Sie dies nicht, es funktioniert unter iOS 12. Es ist auch nicht dokumentiert, was UIWindow in diesem Fall tun sollte. openradar.appspot.com/42372793
steipete
73

Sie müssen je nach tatsächlichem Bedarf unterschiedliche Erkennungen des iPhone X durchführen.

für den Umgang mit der besten (Statusleiste, Navigationsleiste) usw.

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
}

für den Umgang mit der unteren Home-Anzeige (Tabbar) usw.

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
}

für Hintergrundgröße, Vollbildfunktionen usw.

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

Hinweis: Mischen Sie es schließlich mit UIDevice.current.userInterfaceIdiom == .phone
Hinweis: Für diese Methode ist ein LaunchScreen-Storyboard oder die richtigen LaunchImages erforderlich

für Hintergrundverhältnis, Bildlauffunktionen usw.

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
}

Hinweis: Für diese Methode ist ein LaunchScreen-Storyboard oder geeignete LaunchImages erforderlich

für Analysen, Statistiken, Tracking usw.

Holen Sie sich die Maschinenkennung und vergleichen Sie sie mit dokumentierten Werten:

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

So nehmen Sie den Simulator als gültiges iPhone X in Ihre Analyse auf:

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

Um iPhone XS, XS Max und XR einzuschließen, suchen Sie einfach nach Modellen, die mit "iPhone11" beginnen:

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

für faceID-Unterstützung

import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
    if #available(iOS 11.0, *) {
        return LAContext().biometryType == .typeFaceID
    }
    return false
}
Cœur
quelle
Ich hatte gehofft, dass das return LAContext().biometryType == .typeFaceIDfunktionieren würde, selbst wenn der Benutzer canEvaluatePolicy abgelehnt hätte, aber es funktioniert nicht für mich, es kehrt immer noch zurück.none
Jeremy
Nun, @Jeremy, es ist ein dokumentiertes Verhalten, eine Folge der Apple-Datenschutzrichtlinie. Deshalb der Kommentar über der Methode.
Cœur
Ah, ich habe Ihren Kommentar falsch interpretiert. Ich dachte, Sie wollten, dass die Verwendung von canEvaluatePolicy fehlschlägt. Verwenden Sie stattdessen Folgendes. Ich finde es etwas seltsam, dass Sie prüfen dürfen, ob das Gerät eine Gesichts-ID hat, bis der Benutzer auf das Umschalten reagiert, und Sie dann nicht einmal mehr prüfen können. Wie soll ich eine hilfreiche Fehlermeldung bereitstellen, um zu Einstellungen zu wechseln und die Gesichts-ID umzuschalten?
Jeremy
@Jeremy Ich besitze kein iPhone X, also weiß ich es nicht. Vielleicht könnten Sie die Modellerkennung oben ( model == "iPhone10,3" || model == "iPhone10,6") verwenden. Wenn canUseFaceIDfalse zurückgegeben wird, bedeutet dies, dass sie vom Benutzer abgelehnt wurde.
Cœur
1
@MateoOlaya Nichts in meiner Antwort würde von Apple abgelehnt: Sie können alles verwenden.
Cœur
42

Auf diese Weise können Sie das iPhone X- Gerät nach Abmessungen erkennen.

Schnell

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

Ziel c

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

Geben Sie hier die Bildbeschreibung ein

Aber ,

Dies ist nicht ausreichend. Was wäre, wenn Apple das nächste iPhone mit der gleichen Größe wie das iPhone X ankündigen würde? Der beste Weg ist also, die Hardware-Zeichenfolge zu verwenden, um das Gerät zu erkennen.

Für neuere Geräte ist die Hardware-Zeichenfolge wie folgt.

iPhone 8 - iPhone10,1 oder iPhone iPhone

iPhone 8 Plus - iPhone 10,2 oder iPhone 10,5

iPhone X - iPhone10,3 oder iPhone10,6

Jaydeep
quelle
2
Sie sollten [UIDevice currentDevice]anstelle von[[UIDevice alloc] init]
S. Matsepura
Das einzige Problem mit der Hardware-Zeichenfolge ist, dass sie auf dem Simulator nicht funktioniert
wahrscheinlich
38

Überprüfen Sie das Gerätemodell / den Computernamen. Verwenden Sie die Punkt- / Pixelanzahl NICHT direkt in Ihrem Code. Es handelt sich um harten Code und ist für die Gerätehardware bedeutungslos. Das Gerätemodell ist die einzige eindeutige Kennung für einen übereinstimmenden Gerätetyp .

#import <sys/utsname.h>

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

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

Ergebnis:

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

Beziehen Sie sich auf diese Antwort .

Vollständige Code-Implementierung:

#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))
    ];

    return [notchiModels containsObject:GetDeviceModel()];
}
Itachi
quelle
1
Hervorragende Antwort, da der Simulator korrekt funktioniert. Bitte fügen Sie die Zeile #import zum Abschnitt "vollständiger Code" hinzu. Ich habe das beim ersten Versuch verpasst (kopieren / einfügen).
Mpoisot
1
das ist meine bevorzugte Methode. In diesem Wiki finden Sie eine vollständige Liste der Zeichenfolgen für Gerätemodelle. Als Nebenkommentar könnte @ "iphone10,3" auch als harter Code angesehen werden.
YvesLeBorg
1
@YvesLeBorg Ja, es ist wirklich ein kritisches kontroverses Thema. Die Hardware-Modellzeichenfolge hat eine eindeutige Kennung als Bildschirmpunkte für das Gerät, denke ich. Im Allgemeinen wird es für Datenstatistiken verwendet.
Itachi
25
#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)

definiere IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] Grenzen] .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"]

Hinweis: - Seien Sie vorsichtig, es funktioniert nur für die Hochformatausrichtung

Jagveer Singh
quelle
2
Seien Sie vorsichtig, es funktioniert nur für die Ausrichtung im Hochformat
CFIFok
1
Danke dafür. Funktioniert gut. Im Querformat müssen Sie diese Zahlen anpassen. Die magische Zahl von iPhoneX im Querformat ist 375.0
pvella
Es gibt ein paar iPhone Plus / Max / Pro, die nativeScalemit verwenden 3.0, oder?
Itachi
24

Nachdem ich mir alle Antworten angesehen hatte, tat ich Folgendes:

Lösung (Swift 4.1 kompatibel)

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

Verwenden

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

Hinweis

Vor Swift 4.1 können Sie überprüfen, ob die App auf einem Simulator wie folgt ausgeführt wird:

TARGET_OS_SIMULATOR != 0

Ab Swift 4.1 können Sie anhand der Bedingung der Zielumgebungsplattform überprüfen, ob die App auf einem Simulator ausgeführt wird :

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

(Die ältere Methode wird weiterhin funktionieren, aber diese neue Methode ist zukunftssicherer.)

Cloud9999Strife
quelle
Ist Apple damit einverstanden?
Surjeet Rajput
@ commando24 Ja, ich sehe keinen Grund für sie, die App aufgrund dieses Codes abzulehnen.
Cloud9999Strife
18

Alle diese auf Dimensionen basierenden Antworten können auf zukünftigen Geräten zu falschem Verhalten führen. Sie werden heute funktionieren, aber was ist, wenn es nächstes Jahr ein iPhone gibt, das die gleiche Größe hat, aber die Kamera usw. unter dem Glas hat, so dass es keine "Kerbe" gibt? Wenn die einzige Möglichkeit darin besteht, die App zu aktualisieren, ist dies eine schlechte Lösung für Sie und Ihre Kunden.

Sie können auch die Hardware-Modellzeichenfolge wie "iPhone10,1" überprüfen. Dies ist jedoch problematisch, da Apple manchmal unterschiedliche Modellnummern für verschiedene Netzbetreiber auf der ganzen Welt veröffentlicht.

Der richtige Ansatz besteht darin, das obere Layout neu zu gestalten oder die Probleme zu lösen, die Sie mit der Höhe der benutzerdefinierten Navigationsleiste haben (darauf würde ich mich konzentrieren). Wenn Sie sich jedoch entscheiden, keines dieser Dinge zu tun, stellen Sie fest, dass alles, was Sie tun, ein Hack ist, damit dies heute funktioniert , und Sie müssen es irgendwann korrigieren, möglicherweise mehrmals, um die Hacks beizubehalten Arbeiten.

Clarus
quelle
1
Recht. Wenn Sie die Annahme verfeinern, dass die Zahl X immer A ist, wird die Zahl X immer A sein, es sei denn, die Bedingung Y, wenn es B ist, gräbt nur tiefer. Die Größe basiert auf dem von Apple nominierten Sicherheitsbereich, nicht durch Nachdenken.
Tommy
2
Ich werde mir Sorgen um das nächste iPhone machen, wenn es tatsächlich da draußen ist. Ich möchte, dass meine App HEUTE funktioniert.
Vahid Amiri
13

SWIFT 4+ Antwort

iPhone X, XR, XS, XSMAX, 11 Pro, 11 Pro Max:

Hinweis: Benötigen Sie ein echtes Gerät zum Testen

Referenz

 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")
        case "iPhone12,3":
            print("iPhone 11 Pro")
        case "iPhone12,5":
            print("iPhone 11 Pro Max")
        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
    }
}
Jack
quelle
Für Methode 1 können Sie die Eigenschaft "var window" außerhalb der Funktion und nur eine "let" -Konstante darin entfernen (geben Sie UIWindow ein, dh nicht optional). Ich mag diese Antwort, da beim Start self.view.window möglicherweise null und UIApplication.shared.keyWindow ebenfalls null ist, während das Erstellen eines UIWindow auf diese Weise jedes Mal funktioniert.
Rolleric
11

Wiederverwendbare SWIFT 4/5- Erweiterung mit iPhone 11- Unterstützung

    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_11_Pro_Max
        case iPhone_Xr_11
        case iPhone_11_Pro
    }

    public var hasHomeButton: Bool {
        switch type {
        case .iPhone_X_Xs, .iPhone_Xr_11, .iPhone_Xs_11_Pro_Max, .iPhone_11_Pro:
            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_11_Pro_Max
            case 1792: return .iPhone_Xr_11
            case 2426: return .iPhone_11_Pro
            default: return .iPhone_unknown
        }
        }
        return .iPad
   }
}
ale_stro
quelle
2
gute Erweiterung, aber am nützlichsten hier istUIDevice.current.hasHomeButton
WINSergey
1
@ale_stro ist es gut, userInterfaceIdiom zum Bestimmen von Geräten für die universelle App zu verwenden? Die meisten Leute empfehlen dies nicht. Kann es schaden, es zu benutzen?
Shaqir sagte
10

Ja, es ist möglich. Laden Sie die UIDevice-Hardware-Erweiterung herunter (oder installieren Sie sie über den CocoaPod 'UIDevice-Hardware') und verwenden Sie dann:

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

Beachten Sie, dass dies im Simulator nicht funktioniert, sondern nur auf dem tatsächlichen Gerät.

Hendrik
quelle
Alle Gerätecode hier: iphonesoft.fr/2016/10/31/… Beispiel: iPhone X: iPhone10,5 und iPhone10,6
Medhi
Die Hardware-Zeichenfolgen von Wikipedia sagten "iPhone10,3 und iPhone10,6". @ Medhi
Itachi
@Medhi können Sie ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIF‌​IER"]in Simulator verwenden, um die tatsächlichen Werte von Xcode abzurufen .
Cœur
9

Laut der Antwort von @ saswanb handelt es sich um eine Swift 4-Version:

var iphoneX = false
if #available(iOS 11.0, *) {
    if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
        iphoneX = true
    }
}
MattOZ
quelle
Die Statusleiste wird auch außerhalb des sicheren Bereichs betrachtet! Dies wird also falsch positive Ergebnisse zurückgeben! Sie sollte höher als 20 Punkte sein (Höhe der Statusleiste). Dies gibt auch true zurück, wenn das Gerät iPhone Xs, R oder Xs Max ist.
MQoder
Code funktioniert gut, aber Vorsicht: keyWindowist , nilbis die Hauptansicht - Controller genannt hatviewDidAppear
Casey
9

Ich weiß, dass es nur ein Swift ist Lösung ist, aber es könnte jemandem helfen.

Ich habe globals.swiftin jedem Projekt und eines der Dinge, die ich immer hinzufüge, ist DeviceType, das Gerät des Benutzers leicht zu erkennen:

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.maxWH == 896.0
  static var hasNotch: Bool {
    return iPhoneX || iPhoneXRMax
  }
}

Dann, um es zu benutzen:

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

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

Wenn Sie LaunchImagein Ihrem Projekt verwenden, stellen Sie sicher, dass Sie Bilder für alle unterstützten Geräte (wie XS Max, XR) hinzufügen, da UIScreen.main.boundsohne diese keine korrekten Werte zurückgegeben werden.

Budidino
quelle
1
Ein neuer Freund von Swift fragte, wie man das benutzt, nur für den Fall, dass jemand anderes es nicht weiß ... if DeviceType.iPhoneX { //do something for iPhone X notch }else{ // don’t do anything about notch }
Liam Bolling
5

Alle Antworten, die das verwenden, heightsind aus einem Grund nur der halbe Teil der Geschichte. Wenn Sie auf diese Weise prüfen, ob die Geräteorientierung stimmt landscapeLeftoder landscapeRightdie Prüfung fehlschlägt, weil die heightmit der ausgetauscht wird width.

Deshalb sieht meine Lösung in Swift 4.0 so aus:

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
    }
}
DevAndArtist
quelle
Verwenden Sie stattdessen einfach nativeBounds
Leo Dabus
4

Sie sollten nicht davon ausgehen, dass das einzige Gerät, das Apple mit einer anderen UINavigationBar-Höhe veröffentlicht, das iPhone X ist. Versuchen Sie, dieses Problem mit einer allgemeineren Lösung zu lösen. Wenn die Leiste immer 20 Pixel größer als die Standardhöhe sein soll, sollte Ihr Code die Höhe der Leiste um 20 Pixel erhöhen, anstatt sie auf 64 Pixel (44 Pixel + 20 Pixel) festzulegen.

IMcD23
quelle
Welche andere Lösung müssen Sie vorschlagen?
Stephane Mathis
@xaphod gibt es jetzt bessere Antworten.
Cœur
4
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
}
Kiran Sarvaiya
quelle
4

Swift 3 + 4:

ohne dass ein Pixelwert für die Gerätegröße erforderlich ist

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

Beispiel:

if UIApplication.isDeviceWithSafeArea {
     //e.g. change the frame size height of your UITabBar
}
Peter Kreinz
quelle
3
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
alexander.pan
quelle
2
Es wird Ihnen 812 zurückgeben, wenn Sie das Standardbild für das iPhone X hochladen. Bis dahin denke ich, dass es Ihnen die Größe des iPhone 7
zurückgibt
3
- (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;
    }
}
user6788419
quelle
1
Beste Antwort! Ohne dass ein Pixelwert für die Gerätegröße erforderlich ist.
Peter Kreinz
3

Normalerweise benötigt der Programmierer dies, um sich auf oben oder unten zu beschränken, sodass diese Methoden hilfreich sein können

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
}

Für vor iPhone X geben diese Methoden Folgendes zurück: 0

Für iPhone X: 44 und 34 entsprechend

Fügen Sie diese Extras dann einfach zu den oberen oder unteren Einschränkungen hinzu

Andrey
quelle
3

Für diejenigen, die 2001px anstelle von 2436px für die native Grenzhöhe erhalten (wie ich), liegt dies daran, dass Sie Ihre App mit einem älteren SDK vor iOS 11 erstellt haben (Xcode 8 anstelle von Xcode 9). Mit einem älteren SDK zeigt iOS die Apps "Black Boxed" auf dem iPhone X an, anstatt den Bildschirm von Rand zu Rand über die oberste "Sensorkerbe" hinaus zu erweitern. Dies reduziert die Bildschirmgröße, weshalb diese Eigenschaft 2001 anstelle von 2436 zurückgibt.

Die einfachste Lösung besteht darin, nur nach beiden Größen zu suchen, wenn Sie nur an der Geräteerkennung interessiert sind. Ich habe diese Methode zum Erkennen von FaceID verwendet, während ich mit einem älteren Xcode SDK erstellt habe, dessen ENUM-Wert nicht den biometrischen Typ angibt. In dieser Situation schien die Geräteerkennung anhand der Bildschirmhöhe der beste Weg zu sein, um festzustellen, ob das Gerät über FaceID oder TouchID verfügt, ohne Xcode aktualisieren zu müssen.

Jon Summers
quelle
3

Verwenden Sie NICHT die Bildschirmpixelgröße, wie andere Lösungen vorgeschlagen haben. Dies ist schlecht, da dies bei zukünftigen Geräten zu Fehlalarmen führen kann. funktioniert nicht, wenn UIWindow noch nicht gerendert wurde (AppDelegate), funktioniert nicht in Landschafts-Apps und kann im Simulator fehlschlagen, wenn die Skalierung festgelegt ist.

Ich habe stattdessen ein Makro für diesen Zweck erstellt, das sehr einfach zu verwenden ist und sich auf Hardware-Flags stützt, um die oben genannten Probleme zu vermeiden.

Bearbeiten: Aktualisiert, um iPhoneX, iPhone XS, iPhoneXR, iPhoneXS max zu unterstützen


Benutzen:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

Ja, wirklich.


Makro:

Kopieren Sie diese einfach und fügen Sie sie irgendwo ein. Ich bevorzuge den unteren Rand meiner .h-Datei danach @end

#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]);\
})()\
)
Albert Renshaw
quelle
Der einzige Grund, warum ich mir vorstellen kann, iPhoneX zu erkennen, besteht darin, die Kerbe am oberen Bildschirmrand zu vermeiden. In diesem Fall können Sie die Datei safeArea.top überprüfen, um die Größe dieser Kerbe zu ermitteln. Stellen Sie einfach sicher, dass Sie es messen, nachdem UIWindow geladen wurde, also nicht während viewDidLoad, sondern einen Thread-Zyklus nach:if (@available(iOS 11.0, *)) { [UIApplication sharedApplication].keyWindow.safeAreaInsets.top }
Albert Renshaw
2

Ich habe die Antworten Ihrer Mitarbeiter ausgearbeitet und UIDevice schnell erweitert. Ich mag schnelle Aufzählungen und "alles in Ordnung" & atomisiert. Ich habe eine Lösung erstellt, die sowohl auf dem Gerät als auch auf dem Simulator funktioniert.

Vorteile: - einfache Oberfläche, Verwendung zB UIDevice.current.isIPhoneX -UIDeviceModelType Enum bietet Ihnen die Möglichkeit, modellspezifische Funktionen und Konstanten, die Sie in Ihrer App verwenden möchten, z. B. CornerRadius, einfach zu erweitern

Nachteil: - Es handelt sich um eine modellspezifische Lösung, nicht um eine auflösungsspezifische Lösung. - Wenn Apple beispielsweise ein anderes Modell mit denselben Spezifikationen herstellt, funktioniert dies nicht ordnungsgemäß und Sie müssen ein weiteres Modell hinzufügen, damit dies funktioniert. => Sie müssen Ihr Modell aktualisieren App.

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
    }
}
Todestier
quelle
Anstatt zu verwenden Mirror, ist die Verwendung schneller sysctlbynameals in der Cloud9999Strife-Antwort (und auch in meiner Antwort).
Cœur
2

Ich verlasse mich auf die Höhe des Statusleistenrahmens, um festzustellen, ob es sich um ein iPhone X handelt:

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

Dies ist für die Anwendung un Porträt. Sie können die Größe auch entsprechend der Geräteorientierung überprüfen. Bei anderen iPhones ist die Statusleiste möglicherweise ausgeblendet, sodass die Rahmenhöhe gleich ist 0. Auf dem iPhone X wird die Statusleiste niemals ausgeblendet.

Tiois
quelle
Sie können die iPhoneX statusBar folgendermaßen ausblenden controller: - (BOOL)prefersStatusBarHidden { return YES; } Dann ist die Höhe der statusBar 0.
夜 之 星辰
@ 无 夜 之 星辰 Ich überprüfe dies beim Booten im AppDelegate.
Tiois
2

Ich habe den Code von Peter Kreinz verwendet (weil er sauber war und das tat, was ich brauchte), aber dann wurde mir klar, dass er nur funktioniert, wenn sich das Gerät im Hochformat befindet (da die obere Polsterung natürlich oben ist). Also habe ich eine Erweiterung erstellt, um alle zu verarbeiten Ausrichtungen mit den jeweiligen Polsterungen, ohne die Bildschirmgröße zu beeinflussen:

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

Und auf Ihrer Anrufseite haben Sie nur:

let res = UIDevice.current.isIphoneX
rgkobashi
quelle
2

Alternativ können Sie sich den Pod " DeviceKit " ansehen. Nach der Installation müssen Sie lediglich Folgendes überprüfen, um das Gerät zu überprüfen:

import DeviceKit
let device = Device()
if device == .iPhoneX {
  // place your code here
}
Islombek Hasanov
quelle
2

November 2019:

Folgendes verwende ich in all meinen Produktionsprojekten. Beachten Sie, dass dieser Kern ziemlich lang ist.

  1. Hierbei werden keine Berechnungen der Breite oder Höhe verwendet, sondern:
  2. Es überprüft das Gerätezeichenfolgenmodell.
  3. Es besteht nicht das Risiko, dass Ihr Build von Apple abgelehnt wird, da private / undokumentierte APIs verwendet werden.
  4. Funktioniert mit Simulatoren 💯

    import UIKit
    
    class DeviceUtility {
        /// Determines if the current device of the user is an iPhoneX type/variant.
        static var isIphoneXType: Bool {
            get {
                switch UIDevice().type {
                case .iPhoneXR, .iPhoneXS, .iPhoneXSMax, .iPhoneX, .iPhone11, .iPhone11Pro, .iPhone11ProMax: return true
                default: return false
                }
            }
        }
    }
    
    
    public enum DeviceModel : String {
        case simulator     = "simulator/sandbox",
    
        // MARK: - iPods
    
        iPod1              = "iPod 1",
        iPod2              = "iPod 2",
        iPod3              = "iPod 3",
        iPod4              = "iPod 4",
        iPod5              = "iPod 5",
    
        // MARK: - iPads
    
        iPad2              = "iPad 2",
        iPad3              = "iPad 3",
        iPad4              = "iPad 4",
        iPadAir            = "iPad Air ",
        iPadAir2           = "iPad Air 2",
        iPad5              = "iPad 5", //aka iPad 2017
        iPad6              = "iPad 6", //aka iPad 2018
    
        // MARK: - iPad Minis
    
        iPadMini           = "iPad Mini",
        iPadMini2          = "iPad Mini 2",
        iPadMini3          = "iPad Mini 3",
        iPadMini4          = "iPad Mini 4",
    
        // MARK: - iPad Pros
    
        iPadPro9_7         = "iPad Pro 9.7\"",
        iPadPro10_5        = "iPad Pro 10.5\"",
        iPadPro12_9        = "iPad Pro 12.9\"",
        iPadPro2_12_9      = "iPad Pro 2 12.9\"",
    
        // MARK: - iPhones
    
        iPhone4            = "iPhone 4",
        iPhone4S           = "iPhone 4S",
        iPhone5            = "iPhone 5",
        iPhone5S           = "iPhone 5S",
        iPhone5C           = "iPhone 5C",
        iPhone6            = "iPhone 6",
        iPhone6plus        = "iPhone 6 Plus",
        iPhone6S           = "iPhone 6S",
        iPhone6Splus       = "iPhone 6S Plus",
        iPhoneSE           = "iPhone SE",
        iPhone7            = "iPhone 7",
        iPhone7plus        = "iPhone 7 Plus",
        iPhone8            = "iPhone 8",
        iPhone8plus        = "iPhone 8 Plus",
        iPhoneX            = "iPhone X",
        iPhoneXS           = "iPhone XS",
        iPhoneXSMax        = "iPhone XS Max",
        iPhoneXR           = "iPhone XR",
        iPhone11           = "iPhone 11",
        iPhone11Pro        = "iPhone 11 Pro",
        iPhone11ProMax     = "iPhone 11 Pro Max",
    
        // MARK: - Apple TVs
    
        AppleTV            = "Apple TV",
        AppleTV_4K         = "Apple TV 4K",
    
        // MARK: - Unrecognized
    
        unrecognized       = "?unrecognized?"
    }
    
    // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    //MARK: UIDevice extensions
    // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    
    public extension UIDevice {
        var type: DeviceModel {
            var systemInfo = utsname()
            uname(&systemInfo)
            let modelCode = withUnsafePointer(to: &systemInfo.machine) {
                $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                    ptr in String.init(validatingUTF8: ptr)
    
                }
            }
            let modelMap : [ String : DeviceModel ] = [
    
                // MARK: - Simulators
    
                "i386"      : .simulator,
                "x86_64"    : .simulator,
    
                // MARK: - iPod
    
                "iPod1,1"   : .iPod1,
                "iPod2,1"   : .iPod2,
                "iPod3,1"   : .iPod3,
                "iPod4,1"   : .iPod4,
                "iPod5,1"   : .iPod5,
    
                // MARK: - iPad
    
                "iPad2,1"   : .iPad2,
                "iPad2,2"   : .iPad2,
                "iPad2,3"   : .iPad2,
                "iPad2,4"   : .iPad2,
                "iPad3,1"   : .iPad3,
                "iPad3,2"   : .iPad3,
                "iPad3,3"   : .iPad3,
                "iPad3,4"   : .iPad4,
                "iPad3,5"   : .iPad4,
                "iPad3,6"   : .iPad4,
                "iPad4,1"   : .iPadAir,
                "iPad4,2"   : .iPadAir,
                "iPad4,3"   : .iPadAir,
                "iPad5,3"   : .iPadAir2,
                "iPad5,4"   : .iPadAir2,
                "iPad6,11"  : .iPad5, //aka iPad 2017
                "iPad6,12"  : .iPad5,
                "iPad7,5"   : .iPad6, //aka iPad 2018
                "iPad7,6"   : .iPad6,
    
                // MARK: - iPad mini
    
                "iPad2,5"   : .iPadMini,
                "iPad2,6"   : .iPadMini,
                "iPad2,7"   : .iPadMini,
                "iPad4,4"   : .iPadMini2,
                "iPad4,5"   : .iPadMini2,
                "iPad4,6"   : .iPadMini2,
                "iPad4,7"   : .iPadMini3,
                "iPad4,8"   : .iPadMini3,
                "iPad4,9"   : .iPadMini3,
                "iPad5,1"   : .iPadMini4,
                "iPad5,2"   : .iPadMini4,
    
                // MARK: - iPad pro
    
                "iPad6,3"   : .iPadPro9_7,
                "iPad6,4"   : .iPadPro9_7,
                "iPad7,3"   : .iPadPro10_5,
                "iPad7,4"   : .iPadPro10_5,
                "iPad6,7"   : .iPadPro12_9,
                "iPad6,8"   : .iPadPro12_9,
                "iPad7,1"   : .iPadPro2_12_9,
                "iPad7,2"   : .iPadPro2_12_9,
    
                // MARK: - iPhone
    
                "iPhone3,1" : .iPhone4,
                "iPhone3,2" : .iPhone4,
                "iPhone3,3" : .iPhone4,
                "iPhone4,1" : .iPhone4S,
                "iPhone5,1" : .iPhone5,
                "iPhone5,2" : .iPhone5,
                "iPhone5,3" : .iPhone5C,
                "iPhone5,4" : .iPhone5C,
                "iPhone6,1" : .iPhone5S,
                "iPhone6,2" : .iPhone5S,
                "iPhone7,1" : .iPhone6plus,
                "iPhone7,2" : .iPhone6,
                "iPhone8,1" : .iPhone6S,
                "iPhone8,2" : .iPhone6Splus,
                "iPhone8,4" : .iPhoneSE,
                "iPhone9,1" : .iPhone7,
                "iPhone9,3" : .iPhone7,
                "iPhone9,2" : .iPhone7plus,
                "iPhone9,4" : .iPhone7plus,
                "iPhone10,1" : .iPhone8,
                "iPhone10,4" : .iPhone8,
                "iPhone10,2" : .iPhone8plus,
                "iPhone10,5" : .iPhone8plus,
                "iPhone10,3" : .iPhoneX,
                "iPhone10,6" : .iPhoneX,
                "iPhone11,2" : .iPhoneXS,
                "iPhone11,4" : .iPhoneXSMax,
                "iPhone11,6" : .iPhoneXSMax,
                "iPhone11,8" : .iPhoneXR,
                "iPhone12,1" : .iPhone11,
                "iPhone12,3" : .iPhone11Pro,
                "iPhone12,5" : .iPhone11ProMax,
    
                // MARK: - AppleTV
    
                "AppleTV5,3" : .AppleTV,
                "AppleTV6,2" : .AppleTV_4K
            ]
    
            if let model = modelMap[String.init(validatingUTF8: modelCode!)!] {
                if model == .simulator {
                    if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
                        if let simModel = modelMap[String.init(validatingUTF8: simModelCode)!] {
                            return simModel
                        }
                    }
                }
                return model
            }
            return DeviceModel.unrecognized
        }
    }

Verwendung: lassen Sie einfügen: CGFloat = DeviceUtility.isIphoneXType? 50,0: 40,0

Glenn
quelle
Funktioniert perfekt. Vielen Dank. Ich benutze es in einem SwiftUI-Projekt.
LondonGuy
1

Ich musste das gleiche Problem kürzlich lösen. Und während diese Frage definitiv beantwortet wird ("Nein"), kann dies anderen helfen, die ein iPhone X-spezifisches Layoutverhalten benötigen.

Ich war nicht wirklich daran interessiert, ob das Gerät ein iPhone X war. Ich war daran interessiert, ob das Gerät ein gekerbtes Display hatte.

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
}

Sie können auch eine hasOnScreenHomeIndicatorVariable in die gleiche Richtung schreiben (obwohl Sie vielleicht den unteren sicheren Bereich überprüfen?).

Im obigen Abschnitt wird meine Erweiterung UIViewfür den bequemen Zugriff auf die Sicherheitsbereiche unter iOS 10 und früheren Versionen verwendet.

@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
        }
    }
}
Simeon
quelle
1

In Portrait nur verwende ich die Breite des Rahmens Ansicht und Höhe zu überprüfen:

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

}

Die Abmessungen des Hochformatbildschirms sind hier aufgelistet

Geben Sie hier die Bildbeschreibung ein

Lance Samaria
quelle
0

Es gibt mehrere Gründe, um zu wissen, was das Gerät ist.

  1. Sie können die Gerätehöhe (und -breite) überprüfen. Dies ist nützlich für das Layout, aber normalerweise möchten Sie dies nicht tun, wenn Sie das genaue Gerät kennen möchten.

  2. Für Layoutzwecke können Sie auch verwenden UIView.safeAreaInsets.

  3. Wenn Sie den Gerätenamen anzeigen möchten, der beispielsweise zu Diagnosezwecken in eine E-Mail aufgenommen werden soll, können Sie nach dem Abrufen des Gerätemodells mithilfe sysctl ()des entsprechenden Namens den Namen ermitteln:

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