Come posso determinare a livello di codice se la mia app è in esecuzione nel simulatore di iPhone?
-
19-08-2019 - |
Domanda
Come afferma la domanda, vorrei principalmente sapere se il mio codice è in esecuzione nel simulatore, ma sarei anche interessato a conoscere la versione specifica di iPhone in esecuzione o in fase di simulazione.
EDIT: ho aggiunto la parola "a livello di codice" al nome della domanda. Il punto della mia domanda è essere in grado di includere / escludere dinamicamente il codice in base alla versione / simulatore in esecuzione, quindi sarei davvero alla ricerca di qualcosa come una direttiva pre-processore che possa fornirmi queste informazioni.
Soluzione
Già chiesto, ma con un titolo molto diverso.
Quali #define sono impostati da Xcode quando compilazione per iPhone
Ripeterò la mia risposta da lì:
È contenuto nei documenti SDK in " Compilare il codice sorgente in modo condizionale "
La definizione pertinente è TARGET_OS_SIMULATOR, che è definita in /usr/include/TargetConditionals.h all'interno del framework iOS. Nelle versioni precedenti della toolchain, dovevi scrivere:
#include "TargetConditionals.h"
ma questo non è più necessario sull'attuale toolchain (Xcode 6 / iOS8).
Quindi, per esempio, se vuoi controllare che stai funzionando sul dispositivo, dovresti farlo
#if TARGET_OS_SIMULATOR
// Simulator-specific code
#else
// Device-specific code
#endif
a seconda di quale è appropriato per il tuo caso d'uso.
Altri suggerimenti
Codice aggiornato:
Si presume che funzioni ufficialmente.
#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif
Post originale (dal momento che è obsoleto)
Questo codice ti dirà se stai eseguendo un simulatore.
#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
Non direttiva pre-processore, ma questo era quello che stavo cercando quando sono arrivato a questa domanda;
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
//device is simulator
}
Il modo migliore per farlo è:
#if TARGET_IPHONE_SIMULATOR
e non
#ifdef TARGET_IPHONE_SIMULATOR
poiché è sempre stato definito: 0 o 1
C'È UN MODO MIGLIORE ORA!
A partire da Xcode 9.3 beta 4 è possibile utilizzare #if targetEnvironment (simulatore)
per verificare.
#if targetEnvironment(simulator)
//Your simulator code
#endif
Aggiorna
Xcode 10 e iOS 12 SDK supportano anche questo.
In caso di Swift possiamo implementare quanto segue
Siamo in grado di creare struct che ti consente di creare dati strutturati
struct Platform {
static let isSimulator: Bool = {
#if arch(i386) || arch(x86_64)
return true
#endif
return false
}()
}
Quindi, se volessimo rilevare se l'app è stata costruita per dispositivo o simulatore in Swift, allora.
if Platform.isSimulator {
// Do one thing
}
else {
// Do the other
}
Tutte queste risposte sono buone, ma in qualche modo confonde il principiante come me in quanto non chiarisce il controllo di compilazione e il controllo di runtime. Il preprocessore è in anticipo sui tempi di compilazione, ma dovremmo renderlo più chiaro
Questo articolo di blog mostra Come rilevare il simulatore di iPhone? chiaramente
Runtime
Prima di tutto, discutiamo tra poco. UIDevice ti fornisce già informazioni sul dispositivo
[[UIDevice currentDevice] model]
ti restituirà & # 8220; iPhone Simulator & # 8221; o & # 8220; iPhone & # 8221; in base a dove è in esecuzione l'app.
Tempo di compilazione
Comunque ciò che vuoi è usare definisce il tempo di compilazione. Perché? Perché compili la tua app rigorosamente per essere eseguita all'interno del simulatore o sul dispositivo. Apple effettua una definizione chiamata TARGET_IPHONE_SIMULATOR
. Quindi diamo un'occhiata al codice:
#if TARGET_IPHONE_SIMULATOR
NSLog(@"Running in Simulator - no app store or giro");
#endif
Funziona con Swift 4
e Xcode 9.4.1
Usa questo codice:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Le risposte precedenti sono un po 'datate. Ho scoperto che tutto ciò che devi fare è interrogare la macro TARGET_IPHONE_SIMULATOR
( non è necessario includere altri file di intestazione [supponendo che stai codificando per iOS]).
Ho provato TARGET_OS_IPHONE
ma ha restituito lo stesso valore (1) durante l'esecuzione su un dispositivo e un simulatore effettivi, ecco perché consiglio invece di utilizzare TARGET_IPHONE_SIMULATOR
In rapido:
#if (arch(i386) || arch(x86_64))
...
#endif
Da Rileva se l'app è in fase di creazione per dispositivo o simulatore in Swift
Ho avuto lo stesso problema, sia TARGET_IPHONE_SIMULATOR
che TARGET_OS_IPHONE
sono sempre definiti e sono impostati su 1. La soluzione di Pete funziona, ovviamente, ma se ti capita mai di basarsi su qualcosa di diverso da Intel (improbabile, ma chissà), ecco qualcosa che è sicuro finché l'hardware dell'iPhone non cambia (quindi il tuo codice funzionerà sempre per gli iPhone attualmente in circolazione):
#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif
Mettilo in un posto comodo, quindi fai finta che le costanti TARGET_ *
siano state definite correttamente.
Per Swift 4.2 / xCode 10
Ho creato un'estensione su UIDevice, quindi posso facilmente chiedere se il simulatore è in esecuzione.
// 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
}
}
Nel mio AppDelegate ad esempio utilizzo questo metodo per decidere se è necessaria la registrazione per la notifica remota, cosa impossibile per il simulatore.
// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {
// REGISTER FOR SILENT REMOTE NOTIFICATION
application.registerForRemoteNotifications()
}
Qualcuno ha considerato la risposta fornita qui ?
Suppongo che l'equivalente in obiettivo c sarebbe
+ (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);
}
}
Per includere tutti i tipi di " simulatori "
NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
// we are running in a simulator
}
Con Swift 4.2 (Xcode 10), possiamo farlo
#if targetEnvironment(simulator)
//simulator code
#else
#warning("Not compiling for simulator")
#endif
La mia risposta si basa sulla risposta di @Daniel Magnusson e sui commenti di @Nuthatch e @ n.Drake. e lo scrivo per risparmiare un po 'di tempo per gli utenti veloci che lavorano su iOS9 e versioni successive.
Questo è ciò che ha funzionato per me:
if UIDevice.currentDevice().name.hasSuffix("Simulator"){
//Code executing on Simulator
} else{
//Code executing on Device
}
/// Restituisce vero se il suo simulatore e non un dispositivo
public static var isSimulator: Bool {
#if (arch(i386) || arch(x86_64)) && os(iOS)
return true
#else
return false
#endif
}
Apple ha aggiunto il supporto per verificare che l'app sia destinata al simulatore con quanto segue:
#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif
se non ha funzionato nulla, prova
public struct Platform {
public static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
}
}
Questo ha funzionato meglio per me
NSString *name = [[UIDevice currentDevice] name];
if ([name isEqualToString:@"iPhone Simulator"]) {
}
Secondo me, la risposta (presentata sopra e ripetuta sotto):
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
//device is simulator
}
è la risposta migliore perché è ovviamente eseguita in RUNTIME anziché essere una DIRETTIVA COMPILE.