Mendeteksi jika perangkatnya adalah iPhone X

262

Aplikasi iOS saya menggunakan ketinggian khusus untuk UINavigationBar yang menyebabkan beberapa masalah pada iPhone X baru.

Apakah seseorang sudah tahu cara mendeteksi secara program (dalam Objective-C) andal jika aplikasi berjalan di iPhone X?

EDIT:

Tentu saja memeriksa ukuran layar dimungkinkan, namun, saya ingin tahu apakah ada beberapa metode "membangun" seperti TARGET_OS_IPHONEmendeteksi iOS ...

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

EDIT 2:

Saya tidak berpikir, bahwa pertanyaan saya adalah duplikat dari pertanyaan terkait. Tentu saja, ada metode untuk "mengukur" berbagai properti perangkat saat ini dan menggunakan hasil untuk memutuskan perangkat mana yang digunakan. Namun, ini bukan poin sebenarnya dari pertanyaan saya karena saya mencoba untuk menekankan pada edit pertama saya.

Pertanyaan sebenarnya adalah: "Apakah mungkin mendeteksi secara langsung apakah perangkat saat ini adalah iPhone X (mis. Oleh beberapa fitur SDK) atau apakah saya harus menggunakan pengukuran tidak langsung" ?

Dengan jawaban yang diberikan sejauh ini, saya berasumsi bahwa jawabannya adalah "Tidak, tidak ada metode langsung. Pengukuran adalah cara untuk pergi".

Andrei Herford
sumber
iPhone X memiliki resolusi layar yang berbeda dari yang lain.
El Tomato
2
Ya, seperti yang saya sebutkan di edit saya mungkin untuk memeriksa ukuran layar. Namun pertanyaannya adalah, jika ada metode "langsung" untuk menanyakan tipe perangkat daripada pengukuran "tidak langsung" ...
Andrei Herford
3
Penulis hanya ingin mendapatkan jenis perangkat, bukan resolusi layar. Mengapa tidak memeriksa nama mesin secara langsung? @ Lilis benar.
Itachi
2
mengapa Anda tidak menggunakan panduan area aman saja seperti yang direkomendasikan oleh Apple?
holex
4
PENTING, pengembang masa depan: Jangan mendeteksi ini menggunakan ketinggian layar seperti yang disarankan oleh solusi teratas saat ini, itu buruk karena dapat menghasilkan positif palsu untuk perangkat di masa depan; tidak akan berfungsi jika UIWindow belum ditampilkan (seperti pada fungsi init AppDelegate Anda), tidak akan berfungsi di aplikasi lansekap, dan dapat gagal pada simulator jika skala diatur. JANGAN PERNAH menggunakan angka ajaib untuk hal-hal seperti ini! Anda dapat memeriksa flag perangkat keras untuk menjamin kesuksesan seperti yang saya lakukan di sini: stackoverflow.com/a/51511947/2057171
Albert Renshaw

Jawaban:

383

Berdasarkan pertanyaan Anda, jawabannya adalah tidak. Tidak ada metode langsung. Untuk informasi lebih lanjut, Anda dapat memperoleh informasi di sini:

dan

Tinggi iPhone X adalah 2436 px

Dari Ukuran dan resolusi Layar Perangkat :

masukkan deskripsi gambar di sini

Dari Ukuran dan Orientasi Layar Perangkat :

masukkan deskripsi gambar di sini

Swift 3 dan yang lebih baru :

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

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

Berdasarkan pertanyaan Anda sebagai berikut:

Atau gunakan screenSize.heightsebagai float 812.0f not int 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");
    }

Untuk informasi lebih lanjut, Anda dapat merujuk halaman berikut dalam Pedoman Antarmuka Manusia iOS:

Cepat :

Deteksi dengan topNotch:

Jika ada yang mempertimbangkan menggunakan takik untuk mendeteksi iPhoneX, ingat bahwa pada "lansekap" itu sama untuk semua iPhone.

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
}

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

PEMBARUAN :

Jangan menggunakan userInterfaceIdiomproperti untuk mengidentifikasi tipe perangkat, seperti yang dijelaskan oleh dokumentasi untuk userInterfaceIdiom :

Untuk aplikasi universal, Anda dapat menggunakan properti ini untuk menyesuaikan perilaku aplikasi Anda untuk jenis perangkat tertentu. Misalnya, perangkat iPhone dan iPad memiliki ukuran layar yang berbeda, jadi Anda mungkin ingin membuat tampilan dan kontrol yang berbeda berdasarkan jenis perangkat saat ini.

Artinya, properti ini hanya digunakan untuk mengidentifikasi gaya tampilan aplikasi yang berjalan. Namun, aplikasi iPhone (bukan yang universal) dapat diinstal di perangkat iPad melalui App store, dalam hal ini, userInterfaceIdiomakan mengembalikanUIUserInterfaceIdiomPhone juga.

Cara yang benar adalah dengan mendapatkan nama mesin melalui uname. Periksa hal-hal berikut untuk detail:

Anbu.Karthik
sumber
Resolusi iPhone X adalah 2436 x 1125 piksel sesuai dengan: iphonesoft.fr/2017/09/12/…
Medhi
1
@Medhi - resolusi iphone X adalah - 1125 x 2436 piksel (~ kepadatan piksel 458 ppi)
Anbu.Karthik
14
TIDAK! Aplikasi iPhone (bukan alam semesta) dapat diinstal di perangkat iPad melalui App store, dalam hal ini,userInterfaceIdiomakan mengembalikanUIUserInterfaceIdiomPhonejuga. Jawaban ini salah.
Itachi
1
@ThreeCoins, harap perbarui jawaban Anda untuk perangkat plus sesuai saran Leo Dabus. Ini bekerja pada simulator Plus tetapi tidak pada perangkat.
Hiren Gujarati
2
Ini buruk karena dapat menghasilkan positif palsu untuk perangkat masa depan; tidak akan berfungsi jika UIWindow belum dirender (AppDelegate), tidak akan berfungsi di aplikasi lansekap, dan dapat gagal pada simulator jika skala diatur. Anda dapat memeriksa flag perangkat keras untuk menjamin kesuksesan seperti yang saya lakukan di sini: stackoverflow.com/a/51511947/2057171
Albert Renshaw
101

Kemungkinan lain, yang bekerja di iOS 11 dan iOS 12 karena iPhone X adalah satu-satunya dengan takik di bagian atas dan inset 44. Itulah yang saya benar-benar deteksi di sini:

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

Dan tentu saja, Anda mungkin perlu memeriksa insets area aman kiri dan kanan jika Anda berada dalam orientasi lanskap.

Sunting: _window adalah UIWindow dari AppDelegate, di mana pemeriksaan ini dilakukan dalam aplikasi didFinishLaunchingWithOptions.

Jawaban diperbarui untuk iOS 12 untuk memeriksa apakah top> 24 daripada top> 0.

Sunting: Di simulator, Anda dapat pergi ke Perangkat Keras, Toggle Status Bar Panggilan. Melakukan hal itu menunjukkan kepada saya bahwa ketinggian bilah status tidak berubah pada iPhone X di iOS 11 atau iPhone XS iOS 12 saat terlibat dalam panggilan. Semua yang berubah adalah ikon waktu, yang mendapat latar belakang hijau, dalam kedua kasus. Ini mudah:

masukkan deskripsi gambar di sini

saswanb
sumber
5
Insets area aman akan berisi ketinggian bilah status, jika terlihat, di perangkat lain. Memeriksa apakah ini 0 hanya akan memberi tahu Anda jika bilah status terlihat, bukan apakah perangkat itu adalah iPhone X.
IMcD23
3
"Ini mungkin pecah di iPhone Xs atau iPhone 11 ", kata Cook.
Itachi
11
Saya telah beradaptasi sedikit dan menggunakannya if _window.safeAreaInsets != UIEdgeInsets.zerountuk memungkinkan orientasi perangkat apa pun
Fraser
2
Jika Anda tidak ingin menggunakan .top, safeAreaInsets.bottomakan 34 pada iPhone X dan 0 pada perangkat lain
blwinters
7
Peringatan: Jangan gunakan ini, ini rusak pada iOS 12. Ini juga tidak mendokumentasikan apa yang harus dilakukan UIWindow dalam kasus ini. openradar.appspot.com/42372793
steipete
73

Anda harus melakukan berbagai deteksi iPhone X tergantung pada kebutuhan sebenarnya.

untuk berurusan dengan kedudukan tertinggi (statusbar, navbar), dll.

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
}

untuk berurusan dengan indikator home bottom (tabbar), dll.

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
}

untuk ukuran latar belakang, fitur layar penuh, dll.

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

Catatan: akhirnya campur dengan UIDevice.current.userInterfaceIdiom == .phone
Catatan: metode ini harus memiliki storyboard LaunchScreen atau LaunchImages yang tepat

untuk rasio latar belakang, fitur gulir, dll.

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
}

Catatan: metode ini harus memiliki storyboard LaunchScreen atau LaunchImages yang tepat

untuk analitik, statistik, pelacakan, dll.

Dapatkan pengenal mesin dan bandingkan dengan nilai yang didokumentasikan:

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

Untuk memasukkan simulator sebagai iPhone X yang valid dalam analisis Anda:

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

Untuk memasukkan iPhone XS, XS Max dan XR, cukup cari model yang dimulai dengan "iPhone11,":

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

untuk dukungan faceID

import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
    if #available(iOS 11.0, *) {
        return LAContext().biometryType == .typeFaceID
    }
    return false
}
Cur
sumber
Saya berharap bahwa itu return LAContext().biometryType == .typeFaceIDakan bekerja bahkan jika pengguna telah menolak canEvaluatePolicy, tetapi tidak berhasil bagi saya, masih kembali.none
Jeremy
Yah @ Jeremy, ini adalah perilaku yang terdokumentasi, konsekuensi dari kebijakan privasi Apple. Itu sebabnya komentar di atas metode.
Cœur
Ah, saya salah mengartikan komentar Anda. Saya pikir Anda bermaksud menggunakan canEvaluatePolicy bisa gagal, jadi gunakan yang berikut sebagai gantinya. Saya merasa agak aneh bahwa Anda diizinkan memeriksa apakah perangkat memiliki ID Wajah sampai pengguna merespons beralih dan kemudian Anda bahkan tidak dapat memeriksa lagi. Bagaimana saya bisa memberikan pesan kesalahan yang membantu untuk mengatakan pergi ke Pengaturan dan beralih ID Wajah?
Jeremy
@ Jeremy Saya tidak memiliki iPhone X, jadi saya tidak tahu. Mungkin Anda bisa menggunakan deteksi model di atas ( model == "iPhone10,3" || model == "iPhone10,6"), dan jika canUseFaceIDmengembalikan false, maka itu berarti ditolak oleh pengguna.
Cœur
1
@MateoOlaya Tidak ada jawaban saya yang akan ditolak oleh Apple: Anda dapat menggunakan semuanya.
Cœur
42

Anda dapat melakukan ini untuk mendeteksi perangkat iPhone X berdasarkan dimensi.

Cepat

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

Tujuan - C

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

masukkan deskripsi gambar di sini

Tapi ,

Ini bukan cara yang memadai. Bagaimana jika Apple mengumumkan iPhone berikutnya dengan dimensi yang sama dari iPhone X. jadi cara terbaik adalah menggunakan string Hardware untuk mendeteksi perangkat.

Untuk perangkat yang lebih baru, string Perangkat Keras adalah seperti di bawah ini.

iPhone 8 - iPhone10,1 atau iPhone 10,4

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

iPhone X - iPhone10,3 atau iPhone10,6

Jaydeep
sumber
2
Anda harus menggunakan [UIDevice currentDevice]sebagai gantinya[[UIDevice alloc] init]
S. Matsepura
satu-satunya masalah dengan string perangkat keras adalah tidak bekerja pada simulator
quemeful
38

Lihat model perangkat / nama mesin , JANGAN menggunakan jumlah titik / piksel dalam kode Anda secara langsung, itu kode sulit dan tidak berarti untuk perangkat keras perangkat, model perangkat adalah satu-satunya pengidentifikasi unik untuk jenis perangkat yang cocok .

#import <sys/utsname.h>

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

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

Hasil:

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

Lihat jawaban ini .

Implementasi kode lengkap:

#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
sumber
1
Jawaban yang sangat bagus karena menangani simulator dengan benar. Silakan tambahkan baris impor ke bagian "kode lengkap". Saya melewatkan itu (salin / tempel) pada upaya pertama saya.
mpoisot
1
itulah metode yang saya sukai. Lihat wiki ini untuk daftar lengkap string model perangkat. Sebagai komentar sampingan, @ "iphone10,3" juga dapat dilihat sebagai kode keras.
YvesLeBorg
1
@YvesLeBorg Ya, ini benar-benar masalah kontroversial yang kritis. String model perangkat keras memiliki pengidentifikasi unik daripada titik layar untuk perangkat, saya pikir. Secara umum, ini digunakan untuk statistik data.
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)

define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds] .size.height == 812.0)

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

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

Catatan: - Hati-hati, hanya berfungsi untuk orientasi potret

Jagveer Singh
sumber
2
Hati-hati, ini berfungsi baik hanya untuk orientasi potret
CFIFok
1
Terima kasih untuk ini. Bekerja dengan baik. Dalam mode Lansekap Anda perlu menyesuaikan angka-angka itu. Jumlah ajaib iPhoneX dalam mode Lansekap adalah 375.0
pvella
Ada beberapa iPhone Plus / Max / Pro menggunakan nativeScaledengan 3.0, bukan?
Itachi
24

Setelah melihat semua jawaban, inilah yang akhirnya saya lakukan:

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

Menggunakan

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

Catatan

Pra Swift 4.1 Anda dapat memeriksa apakah aplikasi berjalan pada simulator seperti:

TARGET_OS_SIMULATOR != 0

Dari Swift 4.1 dan seterusnya, Anda dapat memeriksa apakah aplikasi berjalan pada simulator menggunakan kondisi platform Target environment :

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

(metode yang lebih lama masih akan berfungsi, tetapi metode baru ini lebih banyak bukti di masa depan)

Cloud9999Strife
sumber
Apakah apel akan baik-baik saja dengan ini?
Surjeet Rajput
@ commando24 Ya, saya tidak melihat alasan bagi mereka untuk menolak aplikasi karena kode ini.
Cloud9999Strife
18

Semua jawaban ini berdasarkan dimensi rentan terhadap perilaku yang salah pada perangkat di masa mendatang. Mereka akan bekerja hari ini, tetapi bagaimana jika ada iPhone tahun depan dengan ukuran yang sama tetapi memiliki kamera, dll. Di bawah kaca sehingga tidak ada "takik?" Jika satu-satunya pilihan adalah memperbarui aplikasi, maka itu adalah solusi yang buruk untuk Anda dan pelanggan Anda.

Anda juga dapat memeriksa string model perangkat keras seperti "iPhone10, 1", tetapi itu bermasalah karena kadang-kadang Apple merilis nomor model yang berbeda untuk operator yang berbeda di seluruh dunia.

Pendekatan yang benar adalah mendesain ulang tata letak teratas, atau menyelesaikan masalah yang Anda hadapi dengan ketinggian bilah navigasi khusus (itulah yang akan saya fokuskan). Tetapi, jika Anda memutuskan untuk tidak melakukan hal-hal tersebut, sadari bahwa apa pun yang Anda lakukan adalah peretasan untuk membuatnya berfungsi hari ini , dan Anda harus memperbaikinya di beberapa titik, mungkin beberapa kali, untuk menjaga peretasan tersebut. kerja.

clarus
sumber
1
Baik. Menyempurnakan asumsi bahwa angka X akan selalu menjadi A ke yang angka X akan selalu menjadi A kecuali kondisi Y ketika akan menjadi B hanya menggali lebih dalam. Ukuran berdasarkan area aman yang ditunjuk Apple, bukan dengan menebak-nebak.
Tommy
2
Saya akan khawatir tentang iPhone berikutnya ketika sebenarnya ada di luar sana. Saya ingin aplikasi saya bekerja HARI INI.
Vahid Amiri
13

SWIFT 4+ Jawab

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

Catatan: Perlu perangkat nyata untuk pengujian

Referensi

 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
    }
}
Mendongkrak
sumber
Untuk metode 1, Anda dapat mengambil properti "var window" di luar func dan hanya "membiarkan" konstan di dalamnya (ketik UIWindow, yaitu tidak opsional). Saya suka jawaban ini sejak saat startup, self.view.window mungkin nihil, dan UIApplication.shared.keyWindow mungkin juga nihil, sedangkan membuat UIWindow dengan cara ini berfungsi setiap saat.
Rolleric
11

SWIFT 4/5 ekstensi dapat digunakan kembali dengan dukungan iPhone 11

    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
sumber
2
ekstensi yang bagus, tetapi yang paling bermanfaat di sini adalahUIDevice.current.hasHomeButton
WINSergey
1
@ale_stro apakah baik menggunakan userInterfaceIdiom untuk menentukan perangkat untuk aplikasi universal? kebanyakan orang tidak merekomendasikan ini. apakah ada salahnya menggunakannya?
shaqir saiyed
10

Ya itu mungkin. Unduh ekstensi UIDevice-Hardware (atau instal melalui CocoaPod 'UIDevice-Hardware') dan kemudian gunakan:

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

Perhatikan bahwa ini tidak akan berfungsi di Simulator, hanya di perangkat yang sebenarnya.

Hendrik
sumber
Semua kode perangkat di sini: iphonesoft.fr/2016/10/31/... Contoh: iPhone X: iPhone10,5 dan iPhone10,6
Medhi
The string Hardware dari wikipedia mengatakan "iPhone10,3 dan iPhone10,6". @Medhi
Itachi
@ Medhi, Anda dapat menggunakan ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIF‌​IER"]dalam Simulator untuk mendapatkan nilai aktual dari Xcode.
Cœur
9

Menurut respons @saswanb, ini adalah versi Swift 4:

var iphoneX = false
if #available(iOS 11.0, *) {
    if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
        iphoneX = true
    }
}
MattOZ
sumber
Bilah status juga dianggap di luar area aman! jadi ini akan mengembalikan positif palsu! Seharusnya lebih tinggi dari 20 titik (ketinggian bilah status). Pengembalian ini juga benar jika perangkatnya adalah iPhone Xs, R atau Xs Max.
MQoder
Kode karya besar, tapi hati-hati: keyWindowadalah nilsampai controller tampilan utama telah disebutviewDidAppear
Casey
9

Saya tahu itu hanya solusi Swift , tetapi bisa membantu seseorang.

Saya miliki globals.swiftdi setiap proyek dan salah satu hal yang selalu saya tambahkan adalah DeviceTypedengan mudah mendeteksi perangkat pengguna:

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

Kemudian untuk menggunakannya:

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

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

Jika Anda menggunakan LaunchImagedalam proyek Anda, pastikan untuk menambahkan gambar untuk semua perangkat yang didukung (seperti XS Max, XR) karena UIScreen.main.boundstidak akan mengembalikan nilai yang tepat tanpa itu.

budidino
sumber
1
Teman yang baru mengenal Swift bertanya bagaimana menggunakan ini, kalau-kalau ada orang lain yang tidak tahu ... if DeviceType.iPhoneX { //do something for iPhone X notch }else{ // don’t do anything about notch }
Liam Bolling
5

Semua jawaban yang menggunakan heighthanya sebagian dari cerita karena satu alasan. Jika Anda akan memeriksa seperti itu ketika orientasi perangkat landscapeLeftatau landscapeRightcek akan gagal, karena heightbertukar denganwidth .

Itu sebabnya solusi saya terlihat seperti ini di Swift 4.0:

extension UIScreen {
    ///
    static var isPhoneX: Bool {
        let screenSize = UIScreen.main.bounds.size
        let width = screenSize.width
        let height = screenSize.height
        return min(width, height) == 375 && max(width, height) == 812
    }
}
DevAndArtist
sumber
Cukup gunakan nativeBounds saja
Leo Dabus
4

Anda tidak boleh berasumsi bahwa satu-satunya perangkat yang Apple rilis dengan ketinggian UINavigationBar yang berbeda adalah iPhone X. Cobalah untuk menyelesaikan masalah ini menggunakan solusi yang lebih umum. Jika Anda ingin bilah selalu 20px lebih besar dari tinggi standarnya, kode Anda harus menambahkan 20px ke ketinggian bilah, alih-alih mengaturnya menjadi 64px (44px + 20px).

IMcD23
sumber
Jadi, solusi apa lagi yang Anda usulkan?
Stephane Mathis
@ xaphod ada jawaban yang lebih baik sekarang.
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
sumber
4

Swift 3 + 4:

tanpa perlu nilai piksel ukuran perangkat

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

Contoh:

if UIApplication.isDeviceWithSafeArea {
     //e.g. change the frame size height of your UITabBar
}
Peter Kreinz
sumber
3
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
alexander.pan
sumber
2
itu akan mengembalikan Anda 812 jika Anda mengunggah gambar Default untuk iPhone X. Sampai kemudian saya pikir itu akan mengembalikan Anda ukuran iPhone 7, meskipun tidak yakin ...
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;
    }
}
pengguna6788419
sumber
1
Jawaban Terbaik! Tanpa perlu nilai piksel ukuran perangkat.
Peter Kreinz
3

Biasanya, Programmer membutuhkannya untuk membatasi ke atas atau bawah, sehingga metode ini dapat membantu

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
}

Untuk sebelum iPhone X metode ini kembali: 0

Untuk iPhone X: 44 dan 34 sesuai

Kemudian tambahkan saja tambahan ini ke batasan atas atau bawah

Andrey
sumber
3

Bagi mereka yang mendapatkan 2001px bukannya 2436px untuk ketinggian batas asli (seperti saya), itu karena Anda membuat aplikasi Anda dengan SDK yang lebih lama, sebelum iOS 11 (Xcode 8 bukannya Xcode 9). Dengan SDK yang lebih lama, iOS akan menampilkan aplikasi "kotak hitam" pada iPhone X alih-alih memperluas layar ujung-ke-ujung, di luar "sensor notch". Ini mengurangi ukuran layar yang mengapa properti itu mengembalikan 2001 bukan 2436.

Solusi paling sederhana adalah dengan hanya memeriksa kedua ukuran jika Anda hanya tertarik pada deteksi perangkat. Saya menggunakan metode ini untuk mendeteksi FaceID sambil membangun dengan Xcode SDK yang lebih tua yang tidak memiliki nilai ENUM yang menentukan jenis biometrik. Dalam situasi ini, deteksi perangkat menggunakan ketinggian layar sepertinya cara terbaik untuk mengetahui apakah perangkat itu memiliki FaceID vs TouchID tanpa harus memperbarui Xcode.

Jon Summers
sumber
3

JANGAN gunakan ukuran piksel layar seperti yang disarankan solusi lain, ini buruk karena dapat menghasilkan hasil positif palsu untuk perangkat di masa mendatang; tidak akan berfungsi jika UIWindow belum dirender (AppDelegate), tidak akan berfungsi di aplikasi lansekap, dan dapat gagal pada simulator jika skala diatur.

Sebagai gantinya, saya telah membuat makro untuk tujuan ini, sangat mudah digunakan dan bergantung pada flag perangkat keras untuk mencegah masalah yang disebutkan di atas.

Sunting: Diperbarui untuk mendukung iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max


Menggunakan:

if (IS_DEVICE_IPHONEX) {
    //do stuff
}

Yup, sungguh.


Makro:

Cukup salin tempel ini di mana saja, saya lebih suka bagian paling bawah dari file .h saya setelah @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
sumber
Satu-satunya alasan saya dapat berpikir untuk mendeteksi iPhoneX adalah untuk menghindari takik di atas layar; jika demikian, Anda dapat memeriksa safeArea.top untuk mendeteksi ukuran takik tersebut. Pastikan Anda mengukurnya setelah UIWindow dimuat, jadi tidak selama viewDidLoad tetapi satu siklus setelah:if (@available(iOS 11.0, *)) { [UIApplication sharedApplication].keyWindow.safeAreaInsets.top }
Albert Renshaw
2

Saya menguraikan jawaban Anda pada jawaban orang lain dan membuat ekstensi cepat pada UIDevice. Saya suka enum cepat dan "semuanya dalam urutan" & dikabutkan. Saya telah menciptakan solusi yang berfungsi baik di perangkat & simulator.

Keuntungan: - antarmuka yang sederhana, misalnya penggunaan UIDevice.current.isIPhoneX - UIDeviceModelTypeenum memberi Anda kemampuan untuk dengan mudah memperluas fitur dan konstanta spesifik model yang ingin Anda gunakan di aplikasi Anda, misalnya cornerRadius

Kekurangan: - ini adalah solusi model spesifik, bukan resolusi spesifik - mis. Jika Apple akan menghasilkan model lain dengan spesifikasi yang sama, ini tidak akan berfungsi dengan benar dan Anda perlu menambahkan model lain untuk membuat ini bekerja => Anda perlu memperbarui Anda aplikasi.

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
    }
}
kuda kematian
sumber
Alih-alih menggunakan Mirror, itu akan lebih cepat digunakan sysctlbynameseperti yang dilakukan dalam Cloud9999Strife menjawab (dan dalam jawaban saya juga).
Cœur
2

Saya mengandalkan ketinggian Frame Status Bar untuk mendeteksi apakah itu iPhone X:

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

Ini untuk aplikasi un portrait. Anda juga dapat memeriksa ukurannya sesuai dengan orientasi perangkat. Selain itu, pada iPhone lainnya, Bilah Status mungkin disembunyikan, sehingga ketinggian bingkai 0. Di iPhone X, Bilah Status tidak pernah disembunyikan.

Tiois
sumber
Anda dapat menyembunyikan status iPhoneX controllerdengan ini: - (BOOL)prefersStatusBarHidden { return YES; } Kemudian tinggi statusBar adalah 0.
无 夜 之 星辰
@ 无 夜 之 星辰 Saya memeriksa ini saat boot di AppDelegate.
Tiois
2

Saya menggunakan kode Peter Kreinz (karena itu bersih dan melakukan apa yang saya butuhkan) tetapi kemudian saya menyadari itu berfungsi tepat ketika perangkat berada di potret (karena bantalan atas akan di atas, jelas) Jadi saya membuat ekstensi untuk menangani semua orientasi dengan bantalan masing-masing, tanpa menyampaikan pada ukuran layar:

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

Dan di situs panggilan Anda, Anda hanya:

let res = UIDevice.current.isIphoneX
rgkobashi
sumber
2

Atau, Anda dapat melihat pod ' DeviceKit '. Setelah terinstal, yang perlu Anda lakukan untuk memeriksa perangkat adalah:

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

November 2019:

Inilah yang saya gunakan di semua proyek produksi saya. Perhatikan bahwa inti ini cukup panjang.

  1. Ini tidak menggunakan perhitungan lebar atau tinggi, melainkan:
  2. Ia memeriksa model string perangkat.
  3. Tidak memiliki risiko mendapatkan bangunan Anda ditolak oleh Apple karena menggunakan API pribadi / tidak berdokumen.
  4. Bekerja dengan simulator 💯

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

Penggunaan: biarkan inset: CGFloat = DeviceUtility.isIphoneXType? 50.0: 40.0

Glenn
sumber
Bekerja dengan sempurna. Terima kasih. Saya menggunakannya dalam proyek SwiftUI.
LondonBeli
1

Saya harus menyelesaikan masalah yang sama baru-baru ini. Dan sementara pertanyaan ini dijawab secara pasti ("Tidak"), ini dapat membantu orang lain yang membutuhkan perilaku tata letak khusus iPhone X.

Saya tidak benar-benar tertarik pada apakah perangkat itu iPhone X. Saya tertarik pada apakah perangkat memiliki layar berlekuk.

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
}

Anda juga bisa menulis hasOnScreenHomeIndicatorvariabel di sepanjang baris yang sama (meskipun periksa area aman bawah, mungkin?).

Di atas menggunakan ekstensi saya aktif UIViewuntuk akses mudah ke insets area aman di iOS 10 dan sebelumnya.

@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
sumber
1

Di Portrait saja saya menggunakan lebar dan tinggi bingkai tampilan untuk memeriksa:

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

}

Dimensi layar potret tercantum di sini

masukkan deskripsi gambar di sini

Lance Samaria
sumber
0

Ada beberapa alasan untuk ingin tahu apa perangkat itu.

  1. Anda dapat memeriksa tinggi dan lebar perangkat. Ini berguna untuk tata letak, tetapi Anda biasanya tidak ingin melakukan itu jika Anda ingin tahu perangkat yang tepat.

  2. Untuk keperluan tata letak, Anda juga dapat menggunakan UIView.safeAreaInsets.

  3. Jika Anda ingin menampilkan nama perangkat, misalnya, untuk dimasukkan dalam email untuk tujuan diagnostik, setelah mengambil model perangkat menggunakan sysctl (), Anda dapat menggunakan yang setara ini untuk mencari nama:

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