Cihazın iPhone X olup olmadığını algılama


262

İOS uygulamam UINavigationBar, yeni iPhone X'de bazı sorunlara yol açan özel bir yükseklik kullanıyor .

Birisi iPhone X üzerinde bir uygulama çalışıyorsa, programlı olarak (Objective-C'de) güvenilir bir şekilde nasıl tespit edileceğini zaten biliyor mu?

DÜZENLE:

Tabii ki ekranın boyutunu kontrol etmek mümkündür, ancak iOS'u TARGET_OS_IPHONEtespit etmek gibi bir "yerleşik" yöntem olup olmadığını merak ediyorum ...

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

DÜZENLEME 2:

Benim sorum bağlantılı sorunun bir kopyası olduğunu sanmıyorum. Tabii ki, mevcut cihazın farklı özelliklerini "ölçmek" ve sonuçları hangi cihazın kullanılacağına karar vermek için kullanmak için yöntemler vardır. Ancak, ilk düzenlememde vurgulamaya çalıştığım halde, sorumun asıl noktası bu değildi.

Asıl soru şu: "Mevcut cihazın bir iPhone X olup olmadığını (örneğin, bazı SDK özellikleriyle) doğrudan tespit etmek mümkün mü yoksa dolaylı ölçümler kullanmak zorunda mıyım ? "

Şimdiye kadar verilen cevaplarla, cevabın "Hayır, doğrudan yöntem yok. Ölçümler gidilecek yol" olduğunu varsayıyorum.


iPhone X'in ekran çözünürlüğü diğerlerinden farklı.
El Tomato

2
Evet, düzenlememde belirttiğim gibi ekran boyutunu kontrol etmek mümkün. Ancak soru, "dolaylı" ölçümler yerine cihaz tipini sorgulamak için "doğrudan" bir yöntem varsa ...
Andrei Herford

3
Yazar sadece ekran çözünürlüğünü değil, cihaz türünü almak istiyor. Neden makine adını doğrudan kontrol etmiyorsunuz? @lubilis haklı.
Itachi

2
neden yalnızca Apple tarafından önerilen güvenli alan kılavuzlarını kullanmıyorsunuz?
holex

4
ÖNEMLİ, gelecekteki geliştiriciler: Mevcut en iyi çözümlerin önerdiği gibi ekran yüksekliğini kullanarak bunu algılamayın, gelecekteki cihazlar için yanlış pozitiflere neden olabileceğinden kötüdür; UIWindow henüz oluşturulmadıysa (AppDelegate init işlevlerinizde olduğu gibi) çalışmaz, yatay uygulamalarda çalışmaz ve ölçek ayarlanırsa simülatörde başarısız olabilir. Böyle şeyler için ASLA sihirli sayılar kullanmayın! Burada yaptığım gibi başarıyı garanti etmek için donanım bayraklarını kontrol edebilirsiniz: stackoverflow.com/a/51511947/2057171
Albert Renshaw

Yanıtlar:


383

Sorunuza dayanarak, cevap hayır. Doğrudan yöntem yoktur. Daha fazla bilgi için bilgiyi buradan edinebilirsiniz:

ve

İPhone X yüksekliği 2436 pikseldir

Gönderen Cihaz Ekran Boyutları ve çözünürlükleri :

resim açıklamasını buraya girin

Gönderen Cihaz ekran boyları ve yönlerine :

resim açıklamasını buraya girin

Swift 3 ve üstü :

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

Amaç-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");
    }
}

Aşağıdaki gibi sorunuza dayanarak:

Veya int değil screenSize.heightfloat olarak kullanın .812.0f812

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

Daha fazla bilgi için iOS İnsan Arabirim Yönergeleri'nde aşağıdaki sayfaya bakabilirsiniz:

Swift :

Şununla algıla topNotch:

İPhoneX algılamak için çentik kullanmayı düşünen varsa, "manzara" tüm iPhone'lar için aynı olduğunu unutmayın.

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
}

Amaç-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;
}

GÜNCELLEME :

UserInterfaceIdiom belgeleriuserInterfaceIdiom açıklandığı için bu özelliği cihaz türünü tanımlamak için kullanmayın :

Evrensel uygulamalar için, bu özelliği uygulamanızın davranışını belirli bir cihaz türüne göre uyarlamak için kullanabilirsiniz. Örneğin, iPhone ve iPad cihazları farklı ekran boyutlarına sahiptir, bu nedenle mevcut cihazın türüne göre farklı görünümler ve kontroller oluşturmak isteyebilirsiniz.

Yani, bu özellik sadece çalışan uygulamanın görünüm stilini tanımlamak için kullanılır. Ancak, iPhone uygulaması (evrensel değil), App Store aracılığıyla iPad cihazına yüklenebilir, bu durumda userInterfaceIdiomda geri döner UIUserInterfaceIdiomPhone.

Doğru yol, makine adını almaktır uname. Ayrıntılar için aşağıdakileri kontrol edin:


IPhone X'nin
Medhi

1
@Medhi - iphone X çözünürlüğü - 1125 x 2436 piksel (~ 458 ppi piksel yoğunluğu)
Anbu.Karthik

14
HAYIR! İPhone uygulaması (evren değil), App Store üzerinden iPad cihazına yüklenebilir, bu durumdauserInterfaceIdiomda geri dönerUIUserInterfaceIdiomPhone. Bu cevap yanlış.
Itachi

1
@ThreeCoins, lütfen Leo Dabus'un önerisine göre artı cihazlar için cevabınızı güncelleyin. Artı simülatörde çalışır, ancak cihazda çalışmaz.
Hiren Gujarati

2
Gelecekteki cihazlar için yanlış pozitif sonuç verebileceğinden bu kötüdür; UIWindow henüz oluşturulmadıysa (AppDelegate) çalışmaz, yatay uygulamalarda çalışmaz ve ölçek ayarlanırsa simülatörde başarısız olabilir. Burada yaptığım gibi başarıyı garanti etmek için donanım bayraklarını kontrol edebilirsiniz: stackoverflow.com/a/51511947/2057171
Albert Renshaw

101

İOS 11 ve iOS 12'de çalışan başka bir olasılık, çünkü iPhone X, üstte bir çentik ve 44 iç metinli tek. Bu gerçekten tespit ettiğim şey:

Objective-C:

    BOOL iPhoneX = NO;
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
        if (mainWindow.safeAreaInsets.top > 24.0) {
            iPhoneX = YES;
        }
    }

Hızlı 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
}

Ve elbette, yatay yönde iseniz, sol ve sağ güvenli alan eklerini kontrol etmeniz gerekebilir.

Düzenleme: _window, AppDelegate'in UIWindow'udur; burada bu kontrol didFinishLaunchingWithOptions uygulamasında yapılır.

Yanıt, iOS 12 için top> 0 yerine top> 24 olup olmadığını kontrol etmek için güncellendi.

Düzenleme: Simülatörde Donanım, Arama İçi Durum Çubuğunu Aç / Kapat'a gidebilirsiniz. Bunu yaptığınızda, bir arama yapıldığında iOS 11'deki iPhone X veya iPhone XS iOS 12'de durum çubuğu yüksekliğinin değişmediğini gösteriyor. Değişen tek şey, her iki durumda da yeşil bir arka plan alan zaman simgesidir. İşte bir çırpıda:

resim açıklamasını buraya girin


5
Güvenli alan ekleri, görünürse, diğer aygıtlarda durum çubuğu yüksekliğini içerir. Bunun 0 olup olmadığını kontrol etmek, yalnızca durum çubuğunun görünür olup olmadığını söyler, cihaz bir iPhone X ise değil.
IMcD23

3
"Bu, iPhone Xs veya iPhone 11'de kırılabilir " dedi Cook.
Itachi

11
Biraz adapte oldum ve if _window.safeAreaInsets != UIEdgeInsets.zeroherhangi bir cihaz yönlendirmesine izin vermek için kullanıyorum
Fraser

2
Kullanmak istemiyorsanız .top, safeAreaInsets.bottomdiğer cihazlarda iPhone X 34 ve 0 olacaktır
blwinters

7
Uyarı: Bunu kullanmayın, iOS 12'de bozulur. Bu durumda UIWindow'un ne yapması gerektiği de belgelenmemiştir. openradar.appspot.com/42372793
steipete

73

Gerçek ihtiyaca göre farklı iPhone X algılamaları yapmalısınız.

üst çentik (durum çubuğu, navbar) vb.

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
}

alt ana gösterge (sekme çubuğu), vb.

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
}

arka plan boyutu, tam ekran özellikleri vb.

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

Not: sonunda UIDevice.current.userInterfaceIdiom == .phone
Not ile karıştırın : bu yöntem bir LaunchScreen film şeridine veya uygun LaunchImages'a sahip olmayı gerektirir

arka plan oranı, kaydırma özellikleri vb.

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
}

Not: Bu yöntem bir LaunchScreen film şeridine veya uygun LaunchImages'a sahip olmayı gerektirir

analiz, istatistik, izleme vb.

Makine tanımlayıcısını alın ve dokümante edilmiş değerlerle karşılaştırın:

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

Simülatörü analitiklerinize geçerli bir iPhone X olarak dahil etmek için:

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

İPhone XS, XS Max ve XR'yi dahil etmek için "iPhone11" ile başlayan modelleri arayın:

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

faceID desteği için

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

return LAContext().biometryType == .typeFaceIDKullanıcı canEvaluatePolicy'i reddetmiş olsa bile işe yarayacağını umuyordum , ama benim için çalışmıyor, hala geri dönüyor.none
Jeremy

@Jeremy, bu, Apple gizlilik politikasının bir sonucu olarak belgelenmiş bir davranış. Bu yüzden yöntemin üstündeki yorum.
Cœur

Ah, yorumunu yanlış yorumladım. CanEvaluatePolicy kullanarak başarısız olabilir demek düşündüm, bu yüzden bunun yerine aşağıdaki kullanın. Kullanıcı geçişe cevap verene kadar cihazın Face ID'ye sahip olup olmadığını kontrol etmenize izin verildiğini biraz garip buluyorum ve daha sonra artık kontrol edemezsiniz. Ayarlar'a gidip Face ID'yi değiştirmeyi söylemek için nasıl yardımcı bir hata mesajı vermem gerekir?
Jeremy

@Jeremy Bir iPhone X'e sahip değilim, bu yüzden bilmiyorum. Belki yukarıdaki model algılamasını ( model == "iPhone10,3" || model == "iPhone10,6") kullanabilirsiniz ve canUseFaceIDfalse döndürürse, kullanıcı tarafından reddedildiği anlamına gelir.
Novur

1
@MateoOlaya Cevabımdaki hiçbir şey Apple tarafından reddedilmez: hepsini kullanabilirsiniz.
Cur

42

İPhone X cihazını boyuta göre tespit etmek için bunu yapabilirsiniz .

hızlı

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

Amaç - C

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

resim açıklamasını buraya girin

Ancak ,

Bu yeterli bir yol değil. Apple bir sonraki iPhone'u iPhone X ile aynı boyutta duyurduysa ne olur? Bu yüzden en iyi yol, cihazı algılamak için Donanım dizesini kullanmaktır.

Daha yeni aygıtlar için Donanım dizesi aşağıdaki gibidir.

iPhone 8 - iPhone10,1 veya iPhone 10,4

iPhone 8 Plus - iPhone10,2 veya iPhone 10,5

iPhone X - iPhone10,3 veya iPhone10,6


2
Bunun [UIDevice currentDevice]yerine kullanmalısınız[[UIDevice alloc] init]
S. Matsepura

donanım dize ile ilgili tek sorun simülatör üzerinde çalışmıyor
quemeful

38

Cihaz modelini / makine adını kontrol edin , kodunuzdaki nokta / piksel sayısını doğrudan KULLANMAYIN, sabit kod ve cihaz donanımı için anlamsızdır , cihaz modeli, eşleşecek bir cihaz türü için tek benzersiz tanımlayıcıdır .

#import <sys/utsname.h>

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

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

Sonuç:

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

Bu cevaba bakınız .

Tam kod uygulaması:

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

1
Simülatörü doğru şekilde kullandığından mükemmel cevap. Lütfen #import satırını "tam kod" bölümüne ekleyin. İlk denememde bunu (kopyala / yapıştır) kaçırdım.
mpoisot

1
bu benim tercih ettiğim yöntem. Aygıt modeli dizelerinin tam listesi için bu wiki'ye bakın . Bir yan yorum olarak, @ "iphone10,3" sabit kod olarak da görüntülenebilir.
YvesLeBorg

1
@YvesLeBorg Evet, bu gerçekten çok tartışmalı bir konu. Donanım modeli dizesi, cihazın ekran noktalarından daha benzersiz bir tanımlayıcıya sahip olduğunu düşünüyorum. Genellikle veri istatistikleri için kullanılır.
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)

IS_IPHONE_X tanımlayın (IS_IPHONE && [[UIScreen mainScreen] sınırları] .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"]

Not: - Dikkatli olun, sadece dikey yönde iyi çalışır


2
Dikkatli olun, sadece portre yönü için iyi çalışır
CFIFok

1
Bunun için teşekkürler. İyi çalışıyor. Manzara modunda bu sayıları ayarlamanız gerekir. Manzara modunda iPhoneX'un sihirli sayısı 375.0
pvella

Birlikte kullanılan birkaç iPhone Plus / Max / Pro nativeScalevar 3.0, değil mi?
Itachi

24

Tüm cevaplara baktıktan sonra yaptığım şey bu:

Çözüm (Swift 4.1 uyumlu)

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

kullanım

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

Not

Ön Swift 4.1 Uygulamanın böyle bir simülatörde çalışıp çalışmadığını kontrol edebilirsiniz:

TARGET_OS_SIMULATOR != 0

Swift 4.1 ve sonrasında, uygulamanın Hedef ortam platformu koşulunu kullanarak bir simülatörde çalışıp çalışmadığını kontrol edebilirsiniz :

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

(eski yöntem yine de çalışır, ancak bu yeni yöntem geleceğin kanıtıdır)


elma bununla iyi olacak mı?
Surjeet Rajput

@ commando24 Evet, bu kod nedeniyle uygulamayı reddetmeleri için herhangi bir neden göremiyorum.
Cloud9999Strife

18

Boyutlara dayalı bu cevapların tümü, gelecekteki cihazlarda yanlış davranışa açıktır. Bugün çalışacaklar, ama gelecek yıl aynı boyutta ancak kamera vb. Camın altında bir iPhone varsa, bu yüzden "çentik" yok? Tek seçenek uygulamayı güncellemekse, sizin ve müşterileriniz için kötü bir çözümdür.

"İPhone10,1" gibi donanım modeli dizesini de kontrol edebilirsiniz, ancak bu sorunludur, çünkü Apple bazen dünyadaki farklı operatörler için farklı model numaraları yayınlar.

Doğru yaklaşım, üst düzeni yeniden tasarlamak veya özel gezinme çubuğu yüksekliği ile yaşadığınız sorunları çözmektir (odaklandığım şey budur). Ancak, bunlardan herhangi birini yapmamaya karar verirseniz, yaptığınız her şeyin bugün işe yaraması için bir hack olduğunu ve hack'leri tutmak için bir noktada, belki de birden fazla kez düzeltmeniz gerektiğini anlayın. Çalışma.


1
Sağ. B olacağı zaman Y koşulu daha derine inmiyorsa, X sayısının her zaman A olacağı varsayımını düzeltmek. Apple tarafından belirlenmiş güvenli bölgeye göre boyut, ikinci tahminle değil.
Tommy

2
Aslında orada olduğunda bir sonraki iPhone için endişeleneceğim. Uygulamamın BUGÜN çalışmasını istiyorum.
Vahid Amiri

13

SWIFT 4+ Cevabı

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

Not: Test için gerçek cihaza ihtiyacınız var

Referans

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

Yöntem 1 için, işlev dışında "var window" özelliğini ve içinde sadece bir "let" sabitini alabilirsiniz (UIWindow yazın, yani isteğe bağlı değil). Bu cevabı başlangıçtan beri seviyorum, self.view.window nil olabilir ve UIApplication.shared.keyWindow da nil olabilirken, bu şekilde bir UIWindow oluşturmak her zaman işe yarar.
Rolleric

11

İPhone 11 desteği ile SWIFT 4/5 yeniden kullanılabilir eklenti

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

2
iyi bir uzantı, ancak burada en yararlıUIDevice.current.hasHomeButton
WINSergey

1
@ale_stro universalInterfaceIdiom'u evrensel uygulama için cihazları belirlemek için kullanmak iyi mi? insanların çoğu bunu önermez. Kullanmanın herhangi bir zararı var mı?
shaqir

10

Evet mümkün. UIDevice-Hardware uzantısını indirin (veya CocoaPod 'UIDevice-Hardware' ile yükleyin) ve ardından şunu kullanın:

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

Bunun Simülatör'de, sadece gerçek cihazda çalışmadığını unutmayın.


Tüm cihaz kodu burada: iphonesoft.fr/2016/10/31/… Örnek: iPhone X: iPhone10,5 ve iPhone10,6
Medhi

Donanım dizeleri gelen wikipedia "iPhone10,3 ve iPhone10,6" dedi. @Medhi
Itachi

@Medhi, Xcode'dan ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIF‌​IER"]gerçek değerleri almak için Simulator'da kullanabilirsiniz .
Cur

9

@ Saswanb'ın yanıtına göre, bu bir Swift 4 sürümüdür:

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

Durum çubuğu da güvenli alanın dışında kabul edilir! bu yanlış pozitif geri dönecek! 20 noktadan (statusbar yüksekliği) yüksek olmalıdır. Bu, cihaz iPhone Xs, R veya Xs Max ise de geçerlidir.
MQoder

Kod inşaat büyük, ama dikkatli olun: keyWindowbir nilana görünümü denetleyicisi olarak adlandırılan kadarviewDidAppear
Casey

9

Bunun sadece bir Swift çözümü olduğunu biliyorum , ama birisine yardımcı olabilir.

Sahibim globals.swiftHer projede ve her zaman eklediğim şeylerden biriDeviceType kullanıcının cihazını kolayca tespit etmektir:

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

Sonra kullanmak için:

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

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

Eğer kullanırsanız LaunchImageprojenizde, çünkü (XS Max, XR gibi) tüm desteklenen cihazlar için resim eklemek için emin olun UIScreen.main.boundsbu olmadan düzgün bir değer döndürmez.


1
Swift'in yeni arkadaşı, başka birinin bilmemesi durumunda bunu nasıl kullanacağını sordu… if DeviceType.iPhoneX { //do something for iPhone X notch }else{ // don’t do anything about notch }
Liam Bolling

5

Kullanan tüm cevaplar heightbir nedenden ötürü hikayenin sadece yarısıdır. Cihaz yönü olduğunda landscapeLeftveya landscapeRightkontrol başarısız olduğunda böyle kontrol edecekseniz , heightile değiştirilir width.

Bu yüzden çözümüm Swift 4.0'da şöyle görünüyor:

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

Bunun yerine nativeBounds kullanın
Leo Dabus

4

Apple'ın farklı bir UINavigationBar yüksekliğiyle piyasaya sürdüğü tek cihazın iPhone X olacağını varsaymamalısınız. Bu sorunu daha genel bir çözüm kullanarak çözmeye çalışın. Çubuğun her zaman varsayılan yüksekliğinden 20 piksel daha büyük olmasını istiyorsanız, kodunuz çubuğun yüksekliğine 64 piksel (44 piksel + 20 piksel) ayarlamak yerine 20 piksel eklemelidir.


Peki, başka hangi çözümü önermek zorundasınız?
Stephane Mathis

@xaphod şimdi daha iyi cevaplar var.
Cur

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
}

4

Hızlı 3 + 4:

herhangi bir cihaz boyutu piksel değerine ihtiyaç duymadan

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

Misal:

if UIApplication.isDeviceWithSafeArea {
     //e.g. change the frame size height of your UITabBar
}

3
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)

2
IPhone X için Varsayılan görüntü yüklerseniz size 812 dönecektir. O zamana kadar size iPhone 7 boyutu döndüreceğini düşünüyorum, ama emin değilim ...
Fahim Parkar

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

1
En iyi cevap! Herhangi bir cihaz boyutuna gerek olmadan piksel değeri.
Peter Kreinz

3

Genellikle, Programcı üst veya alt sınırlama için buna ihtiyaç duyar, bu nedenle bu yöntemler yardımcı olabilir

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
}

İPhone X öncesi için bu yöntemler geri döner: 0

İPhone X için: 44 ve 34 buna göre

Ardından, bu ekstraları üst veya alt kısıtlamalara ekleyin


3

Yerel sınır yüksekliği için (benim gibi) 2436 piksel yerine 2001 piksel alan kullanıcılar için, uygulamanızı iOS 11'den önce (Xcode 9 yerine Xcode 8) daha eski bir SDK ile oluşturmuş olmanızdır. Daha eski bir SDK ile iOS, ekranın üst kenardan kenara, en üstteki "sensör çentiğinin" ötesine genişletilmesi yerine iPhone X'ta "kara kutulu" uygulamaları görüntüler. Bu, ekran boyutunu azaltır, bu nedenle bu özellik 2436 yerine 2001'i döndürür.

En basit çözüm, yalnızca cihaz algılama ile ilgileniyorsanız, her iki boyutu da kontrol etmektir. Biyometrik türü belirleyen ENUM değerine sahip olmayan daha eski bir Xcode SDK ile oluştururken FaceID'i saptamak için bu yöntemi kullandım. Bu durumda, ekran yüksekliğini kullanarak cihaz algılama, cihazın Xcode'u güncellemek zorunda kalmadan FaceID vs TouchID'ye sahip olup olmadığını bilmenin en iyi yolu gibi görünüyordu.


3

Diğer çözümlerin önerdiği gibi ekran piksel boyutunu KULLANMAYIN, bu kötüdür çünkü gelecekteki cihazlar için yanlış pozitiflere neden olabilir; UIWindow henüz oluşturulmadıysa (AppDelegate) çalışmaz, yatay uygulamalarda çalışmaz ve ölçek ayarlanırsa simülatörde başarısız olabilir.

Bunun yerine, bu amaçla bir makro yaptım, kullanımı çok kolay ve yukarıda belirtilen sorunları önlemek için donanım bayraklarına güveniyorum.

Düzenleme: iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max'i desteklemek için güncellendi


Kullanmak:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

Evet, gerçekten.


Makro:

Sadece kopyala bunu herhangi bir yere yapıştırın, sonra benim .h dosyasının en altını tercih ederim @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]);\
})()\
)

İPhoneX'i tespit etmeyi düşünebilmemin tek nedeni ekranın üstündeki çentikten kaçınmak; eğer öyleyse adı geçen çentiğin boyutunu tespit etmek için safeArea.top öğesini kontrol edebilirsiniz. Sadece UIWindow yüklendikten sonra ölçtüğünüzden emin olun, bu yüzden viewDidLoad sırasında değil, bir iş parçacığı döngüsünden sonra:if (@available(iOS 11.0, *)) { [UIApplication sharedApplication].keyWindow.safeAreaInsets.top }
Albert Renshaw

2

Başkalarının cevapları üzerinde durdum ve UIDevice üzerinde hızlı bir uzantı yaptım. Ben hızlı numaralandırmalar ve "sırayla her şey" gibi & atomize. Hem cihazda hem de simülatörde çalışan bir çözüm oluşturdum.

Avantajları: - Basit arayüzü, kullanım mesela UIDevice.current.isIPhoneX -UIDeviceModelType enum, uygulamanızda kullanmak istediğiniz modele özgü özellikleri ve sabitleri kolayca genişletme olanağı sağlar, örneğin cornerRadius

Dezavantaj: - çözünürlüğe özgü değil modele özel bir çözümdür - örneğin Apple aynı özelliklere sahip başka bir model üretecekse, bu düzgün çalışmaz ve bu işi yapmak için başka bir model eklemeniz gerekir => güncellemeniz gerekir Uygulamanın.

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

Kullanmak yerine, Cloud9999Strife cevabında (ve cevabımda da) yapıldığı gibi Mirrorkullanmak daha hızlı olacaktır sysctlbyname.
Cur

2

İPhone X olup olmadığını tespit etmek için Durum Çubuğu Çerçevesi yüksekliğine güveniyorum:

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

Bu uygulama un portre içindir. Boyutu aygıt yönüne göre de kontrol edebilirsiniz. Ayrıca, diğer iPhone'larda Durum Çubuğu gizlenebilir, bu nedenle çerçeve yüksekliği korunur 0. İPhone X'da Durum Çubuğu hiçbir zaman gizlenmez.


Bununla iPhoneX statusBar'ı gizleyebilirsiniz controller: - (BOOL)prefersStatusBarHidden { return YES; } Ardından statusBar'ın yüksekliği 0'dır.
无 夜 之 星辰 28:18

@ 无 夜 之 星辰 Bunu AppDelegate'teki önyükleme zamanında kontrol ediyorum.
Tiois

2

Ben kullanıyordum Peter Kreinz kodunu tüm işlemek için bir uzantı yarattı Yani (temiz ve yaptım gerekli çünkü) ama sonra (üst dolgu üstünde olacağı için açıkçası,) cihazı portre üzerinde sadece zaman çalışır fark ekran boyutuna geçiş yapmadan ilgili dolgularıyla yönlendirme:

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

Ve çağrı sitenizde:

let res = UIDevice.current.isIphoneX

2

Alternatif olarak, ' DeviceKit ' bölmesine bakabilirsiniz . Kurulduktan sonra, cihazı kontrol etmek için tek yapmanız gereken:

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

2

Kasım 2019:

İşte tüm üretim projelerimde kullandığım şeyler. Bu özün oldukça uzun olduğunu unutmayın.

  1. Bu, genişlik veya yükseklik hesaplamaları kullanmaz, aksine:
  2. Aygıt dizesi modelini kontrol eder.
  3. Herhangi bir özel / belgesiz API kullanması nedeniyle yapınızın Apple tarafından reddedilme riski yoktur.
  4. Simülatörlerle çalışır 💯

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

Kullanım: ekleyelim: CGFloat = DeviceUtility.isIphoneXType? 50,0: 40,0


Mükemmel çalışıyor. Teşekkürler. Bir SwiftUI projesinde kullanıyorum.
LondonGuy

1

Son zamanlarda aynı sorunu çözmek zorunda kaldım. Ve bu soru kesin olarak cevaplanırken ("Hayır"), bu, iPhone X'a özgü düzen davranışına ihtiyaç duyan diğerlerine yardımcı olabilir.

Cihazın iPhone X olup olmadığıyla gerçekten ilgilenmedim. Cihazın çentikli bir ekrana sahip olup olmadığıyla ilgileniyordum.

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
}

Ayrıca bir hasOnScreenHomeIndicatorAynı satırlar boyunca değişken (en güvenli alanı kontrol edin, belki?).

Yukarıdakiler UIView, iOS 10 ve önceki sürümlerde güvenli alan eklerine kolay erişim için uzantımı kullanıyor .

@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

Gelen portre sadece denetlemek için görünümün çerçevenin genişliği ve yüksekliği kullanımı:

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

}

Dikey ekran boyutları burada listelenmiştir

resim açıklamasını buraya girin


0

Cihazın ne olduğunu bilmek için birkaç neden var.

  1. Cihazın yüksekliğini (ve genişliğini) kontrol edebilirsiniz. Bu, düzen için kullanışlıdır, ancak kesin cihazı bilmek istiyorsanız genellikle bunu yapmak istemezsiniz.

  2. Düzen amaçları için de kullanabilirsiniz UIView.safeAreaInsets.

  3. Örneğin, tanı amacıyla bir e-postaya dahil edilecek cihaz adını görüntülemek istiyorsanız, cihaz modelini kullanarak aldıktan sonra sysctl (), adı bulmak için bunun eşdeğerini kullanabilirsiniz:

    $ curl http://appledevicenames.com/devices/iPhone10,6
    
    iPhone X
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.