Wie kann ich programmgesteuert feststellen, ob meine App im iPhone-Simulator ausgeführt wird?


270

Wie in der Frage angegeben, möchte ich hauptsächlich wissen, ob mein Code im Simulator ausgeführt wird oder nicht, wäre aber auch daran interessiert, die spezifische iPhone-Version zu kennen, die ausgeführt wird oder simuliert wird.

EDIT: Ich habe das Wort 'programmatisch' zum Fragennamen hinzugefügt. Der Punkt meiner Frage ist, in der Lage zu sein, Code dynamisch einzuschließen / auszuschließen, abhängig davon, welche Version / welcher Simulator ausgeführt wird. Daher würde ich wirklich nach einer Vorprozessor-Direktive suchen, die mir diese Informationen liefern kann.


Ich bin mir nicht sicher, ob eine Pre-Prozessor-Direktive dynamisch ist (obwohl es vielleicht sowieso das ist, wonach Sie gesucht haben). Die Richtlinie bedeutet, dass Sie tatsächlich wussten, wann Sie es bauten, wo es laufen würde.
WiseOldDuck

Antworten:


356

Bereits gefragt, aber mit einem ganz anderen Titel.

Welche #defines werden von Xcode beim Kompilieren für das iPhone eingerichtet?

Ich werde meine Antwort von dort wiederholen:

Es befindet sich in den SDK-Dokumenten unter "Quellcode bedingt kompilieren".

Die relevante Definition ist TARGET_OS_SIMULATOR, die in /usr/include/TargetConditionals.h innerhalb des iOS-Frameworks definiert ist. In früheren Versionen der Toolchain mussten Sie schreiben:

#include "TargetConditionals.h"

Dies ist jedoch in der aktuellen Toolchain (Xcode 6 / iOS8) nicht mehr erforderlich.

Wenn Sie beispielsweise überprüfen möchten, ob Sie auf einem Gerät ausgeführt werden, sollten Sie dies tun

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

je nachdem, was für Ihren Anwendungsfall geeignet ist.


1
Vielen Dank. Ich stimme Ihnen zu, dass dies eine spezifischere Version Ihrer ursprünglichen Frage ist. Wenn Ihre bei meiner ursprünglichen Suche aufgetaucht wäre, hätte ich nicht einmal danach fragen müssen.
Jeffrey Meyer

5
Seien Sie vorsichtig mit diesen Definitionen. Wenn Sie Code mit dem Menüpunkt 'Projekt> Aktives SDK einstellen> Simulator ...' kompilieren, werden als TARGET_IPHONE_SIMULATOR als TARGET_OS_IPHONE beide Variablen definiert! Der einzig richtige Weg, die Logik zu trennen, wird unten von Pete (Danke, Alter) aufgezeigt.
Vadim

5
Beobachten Sie den Unterschied zwischen #if und #ifdef. Für mich war es die Ursache für falsches Verhalten.
Anton

7
Möglicherweise wurde die Notwendigkeit, TargetConditionals einzuschließen, vermieden, seit dies geschrieben wurde, aber ich wollte nur beachten, dass #if TARGET_IPHONE_SIMULATOR jetzt ohne TargetConditionals.h funktioniert.
dmur

1
@ Dimitris Es ist eine gute Praxis. Sie wissen nicht, wie TARGET_OS_SIMULATOR definiert wurde, daher ist! (TARGET_OS_SIMULATOR) möglicherweise nicht identisch mit! TARGET_OS_SIMULATOR
Airsource Ltd

106

Aktualisierter Code:

Dies soll offiziell funktionieren.

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

Ursprünglicher Beitrag (da veraltet)

Dieser Code zeigt an, ob Sie in einem Simulator ausgeführt werden.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif

7
Ab iOS 8 und Xcode 6.1.1 ist TARGET_OS_IPHONE im Simulator wahr.
Malhal

3
Dies funktioniert bei neueren XCode-Versionen nicht mehr
Fabio Napodano

1
Es sei denn, Sie sind im Jahr 2016 und führen einen 64-Bit-Simulator aus. Oder führen Sie 2019 Ihren Code auf einem iPhone mit Intel-Prozessor aus.
Gnasher729

61

Keine Vorprozessor-Direktive, aber das war es, wonach ich gesucht habe, als ich zu dieser Frage kam.

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

9
[model compare:iPhoneSimulator] == NSOrderedSamesollte geschrieben werden als[model isEqualToString:iPhoneSimulator]
user102008

18
Oder [model hasSuffix:@"Simulator"]wenn Sie sich nur für "Simulator" im Allgemeinen interessieren, nicht für iPhone oder iPad im Besonderen. Diese Antwort funktioniert nicht für iPad Simulator :)
Kleiber

Upvoted, weil Nuthatchs Kommentar dies zur besten Antwort insgesamt macht.
Le Mot Juiced

12
Überprüfen Sie in iOS9 das Gerät nameanstelle vonmodel
n.Drake

1
Der Code funktioniert nicht, wenn ein Benutzer Simulatorseinem Gerätenamen ein Wort hinzufügt
mbelsky

55

Der beste Weg, dies zu tun, ist:

#if TARGET_IPHONE_SIMULATOR

und nicht

#ifdef TARGET_IPHONE_SIMULATOR

da es immer definiert ist: 0 oder 1


39

ES GIBT JETZT EINEN BESSEREN WEG!

Ab Xcode 9.3 Beta 4 können Sie dies #if targetEnvironment(simulator)überprüfen.

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

UPDATE
Xcode 10 und iOS 12 SDK unterstützen dies ebenfalls.


1
Dies ist das einzige, was für mich funktioniert, der Rest der Lösungen hat nicht funktioniert.
Vrutin Rathod

Hinweis Dies ist nur in Kürze möglich.
Matt S.

35

Im Falle von Swift können wir Folgendes implementieren

Wir können eine Struktur erstellen, mit der Sie strukturierte Daten erstellen können

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

Dann, wenn wir erkennen wollten, ob eine App für ein Gerät oder einen Simulator in Swift erstellt wird.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}

Meiner Meinung nach die sauberste Implementierung, die x86_64- und i386-Architekturen berücksichtigt. Hat mir geholfen, einen seltsamen Fehler zwischen Gerät und Simulator in Core Data zu überwinden. Du bist der Mann!
Iron John Bonney

5
Auf dem Spielplatz erhalten Sie eine Warnung: "Code nach 'Rückkehr' wird niemals ausgeführt". Also ich denke #if #else #endifwird besser.
DawnSong

12

Funktioniert für Swift 5undXcode 11.3.1

Verwenden Sie diesen Code:

#if targetEnvironment(simulator)
   // Simulator
#else
   // Device
#endif

9

Alle diese Antworten sind gut, aber es verwirrt Neulinge wie mich irgendwie, da es die Kompilierungsprüfung und die Laufzeitprüfung nicht klarstellt. Präprozessor sind vor der Kompilierungszeit, aber wir sollten es klarer machen

Dieser Blog-Artikel zeigt, wie man den iPhone-Simulator erkennt. deutlich

Laufzeit

Lassen Sie uns zunächst kurz diskutieren. UIDevice bietet Ihnen bereits Informationen zum Gerät

[[UIDevice currentDevice] model]

Sie erhalten "iPhone Simulator" oder "iPhone" zurück, je nachdem, wo die App ausgeführt wird.

Kompilierzeit

Sie möchten jedoch die Kompilierungszeit definieren. Warum? Weil Sie Ihre App ausschließlich so kompilieren, dass sie entweder im Simulator oder auf dem Gerät ausgeführt wird. Apple macht eine Definition namens TARGET_IPHONE_SIMULATOR. Schauen wir uns also den Code an:

#if TARGET_IPHONE_SIMULATOR

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

#endif

1
Wie verbessert sich dies gegenüber anderen Antworten?
user151019

@ Mark Es klärt ein wenig
onmyway133

5
Derzeit in Xcode 7, iOS 9 Simulator [[UIDevice currentDevice] model]kehrt iPhoneauch statt iPhone Simulator. Ich denke, dies ist nicht der beste Ansatz.
eMdOS

6

Die vorherigen Antworten sind etwas veraltet. Ich habe festgestellt, dass Sie nur das TARGET_IPHONE_SIMULATORMakro abfragen müssen (Sie müssen keine anderen Header-Dateien einfügen [vorausgesetzt, Sie codieren für iOS]).

Ich habe es versucht, TARGET_OS_IPHONEaber es hat den gleichen Wert (1) zurückgegeben, wenn es auf einem tatsächlichen Gerät und Simulator ausgeführt wird. Deshalb empfehle ich, TARGET_IPHONE_SIMULATORstattdessen zu verwenden.


TARGET_OS_IPHONE ist für Code gedacht, der unter iOS oder MacOS X ausgeführt werden kann. Natürlich möchten Sie, dass sich dieser Code auf einem Simulator wie "iPhone" verhält.
Gnasher729


4

Ich hatte das gleiche Problem, beide TARGET_IPHONE_SIMULATORund TARGET_OS_IPHONEsind immer definiert und auf 1 gesetzt. Petes Lösung funktioniert natürlich, aber wenn Sie jemals auf etwas anderem als Intel aufbauen (unwahrscheinlich, aber wer weiß), ist hier etwas, das sicher ist Solange sich die iPhone-Hardware nicht ändert (Ihr Code funktioniert also immer für die derzeit verfügbaren iPhones):

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

Stellen Sie das an einen geeigneten Ort und tun Sie dann so, als wären die TARGET_*Konstanten korrekt definiert.


4

Hat jemand die hier gegebene Antwort berücksichtigt ?

Ich nehme an, das Ziel-c-Äquivalent wäre

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

4

Für Swift 4.2 / xCode 10

Ich habe eine Erweiterung für UIDevice erstellt, damit ich leicht fragen kann, ob der Simulator ausgeführt wird.

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

In meinem AppDelegate verwende ich diese Methode zum Beispiel, um zu entscheiden, ob eine Registrierung für eine Remote-Benachrichtigung erforderlich ist, was für den Simulator nicht möglich ist.

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

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

1

Um alle Arten von "Simulatoren" einzuschließen

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}

4
Es hat nichts mit Xcode 7 zu tun. Wenn Sie iOS Simulator mit iOS8 (von Xcode 7) ausführen, funktioniert dies. Es wird nicht für iOS9 funktionieren, wo [[UIDevice currentDevice] model] nur "iPhone" zurückgibt, wenn die App von iOS Simulator gestartet wurde
Tesla

warum nicht -[NSString containsString]?
Gobe

1

Mit Swift 4.2 (Xcode 10) können wir dies tun

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif

1
Nur eine weitere Kopie einfügen
J. Doe

0

Meine Antwort basiert auf der Antwort von @Daniel Magnusson und den Kommentaren von @Nuthatch und @ n.Drake. und ich schreibe es, um Zeit für schnelle Benutzer zu sparen, die an iOS9 und höher arbeiten.

Das hat bei mir funktioniert:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}

1
Der Code funktioniert nicht, wenn ein Benutzer Simulatorseinem Gerätenamen ein Wort hinzufügt
mbelsky

Leider UIDevice.current.namemeldet XCode 8 den Namen des Computers, auf dem der Simulator ausgeführt wird (normalerweise so etwas wie "Simons MacBook Pro"), sodass der Test unzuverlässig geworden ist. Ich bin immer noch auf der Suche nach einem sauberen Weg, um das Problem zu beheben.
Michael

0

/// Gibt true zurück, wenn der Simulator und kein Gerät vorhanden sind

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

0

Apple hat folgende Unterstützung für die Überprüfung der App für den Simulator hinzugefügt:

#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif

0

Wenn nichts funktioniert hat, versuchen Sie dies

public struct Platform {

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

}

-4

Meiner Meinung nach die Antwort (oben dargestellt und unten wiederholt):

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

ist die beste Antwort, da sie offensichtlich bei RUNTIME ausgeführt wird und keine COMPILE DIRECTIVE ist.


11
Ich bin nicht einverstanden. Dieser Code landet in Ihrem Produkt, während eine Compiler-Direktive die - auf dem Gerät unnötige - Routine fernhält.
neun Steine

1
Die Compiler-Direktiven funktionieren, weil das Gerät und die Simulatoren völlig unterschiedliche Kompilierungsziele sind - dh Sie würden nicht für beide dieselbe Binärdatei verwenden. Es muss auf verschiedene Hardware kompiliert werden, daher ist es in diesem Fall sinnvoll.
Brad Parks

Bei RUNTIME ausgeführt zu werden, ist die schlechteste Antwort.
Gnasher729

-4

Das hat bei mir am besten funktioniert

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


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

}

2
Unter Xcode 7.3 kehrt das iPhone 6 Plus Simulator zurück "iPhone".
Eric
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.