Bagaimana saya bisa menentukan secara program apakah aplikasi saya berjalan di simulator iphone?

270

Sebagai pertanyaan menyatakan, saya terutama ingin tahu apakah kode saya berjalan di simulator, tetapi juga tertarik untuk mengetahui versi iphone spesifik yang sedang berjalan atau sedang disimulasikan.

EDIT: Saya menambahkan kata 'secara terprogram' ke nama pertanyaan. Inti dari pertanyaan saya adalah untuk dapat secara dinamis memasukkan / mengecualikan kode tergantung pada versi / simulator yang sedang berjalan, jadi saya benar-benar akan mencari sesuatu seperti arahan pra-prosesor yang dapat memberikan saya info ini.

Jeffrey Meyer
sumber
Saya tidak yakin arahan pra-prosesor bersifat dinamis (meskipun mungkin itu yang Anda cari). Arahan berarti bahwa Anda benar-benar tahu, ketika Anda membangunnya, di mana ia akan berakhir.
WiseOldDuck

Jawaban:

356

Sudah ditanya, tetapi dengan judul yang sangat berbeda.

Apa definisi yang diatur oleh Xcode saat mengkompilasi untuk iPhone

Saya akan mengulangi jawaban saya dari sana:

Ada dalam dokumen SDK di bawah "Kompilasi kode sumber secara kondisional"

Definisi yang relevan adalah TARGET_OS_SIMULATOR, yang didefinisikan dalam /usr/include/TargetConditionals.h dalam kerangka iOS. Pada versi sebelumnya dari toolchain, Anda harus menulis:

#include "TargetConditionals.h"

tetapi ini tidak lagi diperlukan pada rantai alat saat ini (Xcode 6 / iOS8).

Jadi, misalnya, jika Anda ingin memeriksa apakah Anda menjalankan perangkat, Anda harus melakukannya

#if TARGET_OS_SIMULATOR
    // Simulator-specific code
#else
    // Device-specific code
#endif

tergantung mana yang sesuai untuk kasus penggunaan Anda.

Airsource Ltd
sumber
1
Terima kasih. Saya setuju dengan Anda ini adalah versi yang lebih spesifik dari pertanyaan awal Anda. Jika pencarian Anda muncul di pencarian asli saya, saya bahkan tidak perlu bertanya.
Jeffrey Meyer
5
Hati-hati dengan definisi ini. Saat Anda mengkompilasi kode dengan item menu 'Project> Set Active SDK> Simulator…', seperti TARGET_IPHONE_SIMULATOR sebagai variabel TARGET_OS_IPHONE, keduanya didefinisikan! Jadi satu-satunya cara yang tepat untuk memisahkan logika ditunjukkan di bawah ini oleh Pete (Terima kasih Bung).
Vadim
5
Tonton perbedaan # jika dan # jika ada. Bagi saya itu adalah penyebab perilaku yang salah.
Anton
7
Mungkin kebutuhan untuk memasukkan TargetConditional telah dihilangkan sejak ini ditulis, tetapi hanya ingin mencatat bahwa #jika TARGET_IPHONE_SIMULATOR berfungsi tanpa menyertakan TargetConditionals.h sekarang.
Dmur
1
@ Dimitris Ini latihan yang bagus. Anda tidak tahu bagaimana TARGET_OS_SIMULATOR telah didefinisikan, jadi! (TARGET_OS_SIMULATOR) mungkin tidak sama dengan! TARGET_OS_SIMULATOR
Airsource Ltd
106

Kode yang diperbarui:

Ini dimaksudkan untuk bekerja secara resmi.

#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif

Pos asli (sejak usang)

Kode ini akan memberi tahu Anda jika Anda menjalankan simulator.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
Pete
sumber
7
Pada iOS 8 dan Xcode 6.1.1 TARGET_OS_IPHONE benar pada simulator.
Malhal
3
ini tidak lagi menjadi masalah pada versi
XCode yang
1
Kecuali Anda berada di tahun 2016 dan menjalankan simulator 64 bit. Atau di 2019 dan jalankan kode Anda di iPhone dengan prosesor Intel.
gnasher729
61

Bukan arahan pra-prosesor, tapi ini yang saya cari ketika saya sampai pada pertanyaan ini;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}
Daniel Magnusson
sumber
9
[model compare:iPhoneSimulator] == NSOrderedSameharus ditulis sebagai[model isEqualToString:iPhoneSimulator]
user102008
18
Atau [model hasSuffix:@"Simulator"]jika Anda hanya peduli tentang "simulator" secara umum, bukan iPhone atau iPad pada khususnya. Jawaban ini tidak akan berfungsi untuk simulator iPad :)
Nuthatch
Terpilih karena komentar Nuthatch menjadikan ini jawaban terbaik di toto.
Le Mot Juiced
12
Di iOS9, periksa perangkat namealih-alihmodel
n. Ambil
1
Kode tidak akan berfungsi jika pengguna menambahkan Simulatorkata dalam nama perangkatnya
mbelsky
55

Cara terbaik untuk melakukan ini adalah:

#if TARGET_IPHONE_SIMULATOR

dan tidak

#ifdef TARGET_IPHONE_SIMULATOR

karena selalu didefinisikan: 0 atau 1

Taranfx
sumber
39

ADA CARA YANG LEBIH BAIK SEKARANG!

Pada Xcode 9.3 beta 4 Anda dapat menggunakannya #if targetEnvironment(simulator)untuk memeriksa.

#if targetEnvironment(simulator)
//Your simulator code
#endif

UPDATE
Xcode 10 dan iOS 12 SDK juga mendukung ini.

Stefan Vasiljevic
sumber
1
Ini adalah satu-satunya yang berfungsi untuk saya, sisa solusi tidak bekerja.
Vrutin Rathod
Catatan Ini hanya cepat.
Matt S.
35

Dalam kasus Swift kita dapat menerapkan yang berikut

Kami dapat membuat struct yang memungkinkan Anda untuk membuat data terstruktur

struct Platform {
    static var isSimulator: Bool {
        #if targetEnvironment(simulator)
            // We're on the simulator
            return true
        #else
            // We're on a device
             return false
        #endif
    }
}

Kemudian Jika kita ingin Mendeteksi apakah aplikasi sedang dibangun untuk perangkat atau simulator di Swift, maka.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}
Nischal Hada
sumber
Implementasi terbersih menurut saya, dan itu menyumbang arsitektur x86_64 dan i386. Membantu saya mengatasi bug perangkat vs. simulator aneh di Core Data. Kamulah orangnya!
Iron John Bonney
5
Di Playground, Anda akan mendapat peringatan, "Kode setelah 'kembali' tidak akan pernah dieksekusi". Jadi saya pikir #if #else #endifakan lebih baik.
DawnSong
12

Bekerja untuk Swift 5danXcode 11.3.1

Gunakan kode ini:

#if targetEnvironment(simulator)
   // Simulator
#else
   // Device
#endif
Haroldo Gondim
sumber
9

Semua jawaban itu baik, tetapi entah bagaimana membingungkan pemula seperti saya karena tidak mengklarifikasi pemeriksaan kompilasi dan pengecekan runtime. Preprosesor ada sebelum waktu kompilasi, tetapi kita harus membuatnya lebih jelas

Artikel blog ini menunjukkan Cara mendeteksi simulator iPhone?jelas

Runtime

Pertama-tama, mari kita bahas sebentar lagi. UIDevice memberi Anda informasi yang sudah ada tentang perangkat

[[UIDevice currentDevice] model]

akan mengembalikan "Simulator iPhone" atau "iPhone" kepada Anda sesuai dengan tempat aplikasi berjalan.

Waktu kompilasi

Namun yang Anda inginkan adalah menggunakan definisi waktu kompilasi. Mengapa? Karena Anda mengkompilasi aplikasi secara ketat untuk dijalankan di dalam Simulator atau di perangkat. Apple membuat mendefinisikan disebut TARGET_IPHONE_SIMULATOR. Jadi mari kita lihat kodenya:

#if TARGET_IPHONE_SIMULATOR

NSLog(@"Running in Simulator - no app store or giro");

#endif
onmyway133
sumber
1
Bagaimana cara meningkatkan jawaban lain?
mmmmmm
@Mark Ini mengklarifikasi sedikit
onmyway133
5
Saat ini, di Xcode 7, iOS 9 Simulator [[UIDevice currentDevice] model]kembali iPhonejuga bukan iPhone Simulator. Jadi, saya pikir ini bukan pendekatan terbaik.
eMdOS
6

Jawaban sebelumnya sedikit tertanggal. Saya menemukan bahwa semua yang perlu Anda lakukan adalah kueri TARGET_IPHONE_SIMULATORmakro ( tidak perlu menyertakan file header lainnya [dengan asumsi Anda mengkode untuk iOS]).

Saya mencoba TARGET_OS_IPHONEtetapi mengembalikan nilai yang sama (1) ketika berjalan pada perangkat dan simulator yang sebenarnya, itu sebabnya saya sarankan menggunakan TARGET_IPHONE_SIMULATORsebagai gantinya.

Stunner
sumber
TARGET_OS_IPHONE adalah untuk kode yang mungkin berjalan di iOS atau di MacOS X. Jelas Anda ingin kode itu berperilaku seperti "iPhone" di simulator.
gnasher729
6

Dengan cepat:

#if (arch(i386) || arch(x86_64))
...            
#endif

Dari Deteksi jika aplikasi sedang dibangun untuk perangkat atau simulator di Swift

CedricSoubrie
sumber
Untuk membedakan antara aplikasi mac: #jika (arch (i386) || arch (x86_64)) &&! Os (OSX) // kita berada di simulator yang berjalan di mac, dan bukan aplikasi mac. (Untuk kode lintas platform termasuk dalam target mac)
Bobjt
4

Saya memiliki masalah yang sama, keduanya TARGET_IPHONE_SIMULATORdan TARGET_OS_IPHONEselalu didefinisikan, dan ditetapkan ke 1. Solusi Pete bekerja, tentu saja, tetapi jika Anda pernah membangun sesuatu selain intel (tidak mungkin, tetapi siapa yang tahu), inilah sesuatu yang aman seperti selama perangkat keras iphone tidak berubah (jadi kode Anda akan selalu berfungsi untuk iPhone yang saat ini ada di sana):

#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif

Letakkan itu di tempat yang nyaman, dan kemudian berpura-pura bahwa TARGET_*konstanta didefinisikan dengan benar.


sumber
4

Adakah yang mempertimbangkan jawaban yang diberikan di sini ?

Saya kira persamaan objektif-c akan menjadi

+ (BOOL)isSimulator {
    NSOperatingSystemVersion ios9 = {9, 0, 0};
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    if ([processInfo isOperatingSystemAtLeastVersion:ios9]) {
        NSDictionary<NSString *, NSString *> *environment = [processInfo environment];
        NSString *simulator = [environment objectForKey:@"SIMULATOR_DEVICE_NAME"];
        return simulator != nil;
    } else {
        UIDevice *currentDevice = [UIDevice currentDevice];
        return ([currentDevice.model rangeOfString:@"Simulator"].location != NSNotFound);
    }
}
Vijay Sharma
sumber
4

Untuk Swift 4.2 / xCode 10

Saya membuat ekstensi di UIDevice, jadi saya dapat dengan mudah menanyakan apakah simulator berjalan.

// UIDevice+CheckSimulator.swift

import UIKit

extension UIDevice {

    /// Checks if the current device that runs the app is xCode's simulator
    static func isSimulator() -> Bool {        
        #if targetEnvironment(simulator)
            return true
        #else
            return false
        #endif
    }
}

Di AppDelegate saya misalnya saya menggunakan metode ini untuk memutuskan apakah mendaftar untuk notifikasi jarak jauh diperlukan, yang tidak mungkin untuk simulator.

// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {

    // REGISTER FOR SILENT REMOTE NOTIFICATION
    application.registerForRemoteNotifications()
}
LukeSideWalker
sumber
1

Untuk memasukkan semua jenis "simulator"

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}
jeffr
sumber
4
Ini tidak ada hubungannya dengan Xcode 7. Jika Anda menjalankan iOS Simulator dengan iOS8 (dari Xcode 7) maka ini akan berfungsi. Ini tidak akan berfungsi untuk iOS9 di mana [[UIDevice currentDevice] model] hanya mengembalikan "iPhone" jika aplikasi diluncurkan dari iOS Simulator
Stefan
mengapa tidak -[NSString containsString]?
Gobe
1

Dengan Swift 4.2 (Xcode 10), kita dapat melakukan ini

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif
iHS
sumber
1
Cuma copy paste lainnya
J. Doe
0

Jawaban saya didasarkan pada jawaban @Daniel Magnusson dan komentar @Nuthatch dan @ n. Rem. dan saya menulisnya untuk menghemat waktu bagi pengguna cepat yang menggunakan iOS9 dan seterusnya.

Inilah yang bekerja untuk saya:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}
euthimis87
sumber
1
Kode tidak akan berfungsi jika pengguna menambahkan Simulatorkata dalam nama perangkatnya
mbelsky
Sayangnya dengan XCode 8 UIDevice.current.namemelaporkan nama mesin yang dijalankan oleh Simulator (biasanya sekitar "Simon's MacBook Pro" sekarang) sehingga pengujian menjadi tidak dapat diandalkan. Saya masih mencari cara yang bersih untuk memperbaikinya.
Michael
0

/// Mengembalikan nilai true jika simulator dan bukan perangkat

public static var isSimulator: Bool {
    #if (arch(i386) || arch(x86_64)) && os(iOS)
        return true
    #else
        return false
    #endif
}
Pratyush Pratik
sumber
0

Apple telah menambahkan dukungan untuk memeriksa aplikasi yang ditargetkan untuk simulator dengan yang berikut:

#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif
David Corbin
sumber
0

jika tidak ada yang berhasil, coba ini

public struct Platform {

    public static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
    }

}
Aklesh Rathaur
sumber
-4

Menurut pendapat saya, jawabannya (disajikan di atas dan diulang di bawah):

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}

adalah jawaban terbaik karena itu jelas dieksekusi pada RUNTIME dibandingkan menjadi SEGERA DIRECTIVE.

pengguna1686700
sumber
11
Saya tidak setuju. Kode ini berakhir di produk Anda, sedangkan arahan kompiler membuat rutin - pada perangkat tidak perlu - keluar.
sembilan batu
1
Arahan kompiler berfungsi karena perangkat dan simulator adalah target kompilasi yang sama sekali berbeda - yaitu Anda tidak akan menggunakan biner yang sama pada keduanya. Ini memiliki dikompilasi untuk hardware yang berbeda, sehingga masuk akal dalam kasus itu.
Brad Parks
Dieksekusi di RUNTIME membuatnya menjadi jawaban yang paling buruk .
gnasher729
-4

Ini yang terbaik untuk saya

NSString *name = [[UIDevice currentDevice] name];


if ([name isEqualToString:@"iPhone Simulator"]) {

}
Mani
sumber
2
Pada Xcode 7.3, iPhone 6 Plus Simulator kembali "iPhone".
Eric