¿Cómo puedo determinar mediante programación si mi aplicación se está ejecutando en el simulador de iPhone?

270

Como dice la pregunta, principalmente me gustaría saber si mi código se está ejecutando o no en el simulador, pero también estaría interesado en conocer la versión específica del iPhone que se está ejecutando o simulando.

EDITAR: agregué la palabra 'programáticamente' al nombre de la pregunta. El punto de mi pregunta es poder incluir / excluir dinámicamente el código dependiendo de la versión / simulador que se esté ejecutando, por lo que realmente estaría buscando algo como una directiva de preprocesador que pueda proporcionarme esta información.

Jeffrey Meyer
fuente
No estoy seguro de que una directiva de preprocesador sea dinámica (aunque de todos modos podría ser lo que estaba buscando). La directiva significa que realmente sabías, cuando la construiste, dónde terminaría corriendo.
WiseOldDuck

Respuestas:

356

Ya preguntado, pero con un título muy diferente.

¿Qué #defines configura Xcode al compilar para iPhone?

Repetiré mi respuesta desde allí:

Está en los documentos del SDK en "Compilación de código fuente condicionalmente"

La definición relevante es TARGET_OS_SIMULATOR, que se define en /usr/include/TargetConditionals.h dentro del marco de iOS. En versiones anteriores de la cadena de herramientas, tenía que escribir:

#include "TargetConditionals.h"

pero esto ya no es necesario en la cadena de herramientas actual (Xcode 6 / iOS8).

Entonces, por ejemplo, si desea verificar que se está ejecutando en el dispositivo, debe hacer

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

dependiendo de cuál sea apropiado para su caso de uso.

Airsource Ltd
fuente
1
Gracias. Estoy de acuerdo con usted, esta es una versión más específica de su pregunta original. Si el tuyo hubiera aparecido en mi búsqueda original, ni siquiera habría necesitado preguntar.
Jeffrey Meyer
55
Tenga cuidado con estas definiciones. Cuando compila código con el elemento de menú 'Proyecto> Establecer Active SDK> Simulador ...', ¡como TARGET_IPHONE_SIMULATOR como TARGET_OS_IPHONE las variables están definidas! Entonces, la única forma correcta de separar la lógica es señalada a continuación por Pete (Gracias amigo).
Vadim el
55
Mira la diferencia #if y #ifdef. Para mí fue la causa del comportamiento incorrecto.
Anton
77
Quizás la necesidad de incluir TargetConditionals se ha obviado desde que se escribió esto, pero solo quería señalar que #if TARGET_IPHONE_SIMULATOR funciona sin incluir TargetConditionals.h ahora.
dmur
1
@ Dimitris Es una buena práctica. No sabes cómo se ha definido TARGET_OS_SIMULATOR, por lo que! (TARGET_OS_SIMULATOR) puede no ser idéntico a! TARGET_OS_SIMULATOR
Airsource Ltd
106

Código actualizado:

Se supone que esto funciona oficialmente.

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

Publicación original (desde obsoleto)

Este código le dirá si está ejecutando en un simulador.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
Pete
fuente
77
A partir de iOS 8 y Xcode 6.1.1, el TARGET_OS_IPHONE es verdadero en el simulador.
malhal
3
esto ya no funciona en las nuevas versiones de XCode
Fabio Napodano el
1
A menos que esté en 2016 y ejecute un simulador de 64 bits. O en 2019 y ejecute su código en un iPhone con procesador Intel.
gnasher729
61

No es una directiva previa al procesador, pero esto era lo que estaba buscando cuando llegué a esta pregunta;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}
Daniel Magnusson
fuente
9
[model compare:iPhoneSimulator] == NSOrderedSamedebe escribirse como[model isEqualToString:iPhoneSimulator]
user102008
18
O [model hasSuffix:@"Simulator"]si solo te importa el "simulador" en general, no el iPhone o iPad en particular. Esta respuesta no funcionará para el simulador de iPad :)
Trepatroncos
Votado porque el comentario de trepatroncos hace que esta sea la mejor respuesta en toto.
Le Mot Juiced
12
En iOS9, verifique el dispositivo en namelugar demodel
n.Drake
1
El código no funcionará si un usuario agrega Simulatorpalabras en el nombre de su dispositivo
mbelsky
55

La mejor manera de hacer esto es:

#if TARGET_IPHONE_SIMULATOR

y no

#ifdef TARGET_IPHONE_SIMULATOR

ya que siempre está definido: 0 o 1

Taranfx
fuente
39

¡HAY UNA MEJOR MANERA AHORA!

A partir de Xcode 9.3 beta 4 puede usar #if targetEnvironment(simulator)para verificar.

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

ACTUALIZAR
Xcode 10 y iOS 12 SDK también lo admiten.

Stefan Vasiljevic
fuente
1
Esto es lo único que funciona para mí, el resto de las soluciones no funcionaron.
Vrutin Rathod
Nota Esto es solo en Swift.
Matt S.
35

En el caso de Swift podemos implementar los siguientes

Podemos crear una estructura que le permita crear datos estructurados

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

Entonces, si quisiéramos detectar si la aplicación se está construyendo para dispositivo o simulador en Swift, entonces.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}
Nischal Hada
fuente
Implementación más limpia en mi opinión, y explica las arquitecturas x86_64 e i386. Me ayudó a superar un error extraño de dispositivo vs. simulador en Core Data. ¡Eres el hombre!
Iron John Bonney
55
En Playground, recibirá una advertencia, "El código después de 'return' nunca se ejecutará". Entonces creo #if #else #endifque será mejor.
DawnSong
12

Trabaja para Swift 5yXcode 11.3.1

Usa este código:

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

Todas esas respuestas son buenas, pero de alguna manera confunde a los novatos como yo, ya que no aclara la verificación de compilación y la verificación de tiempo de ejecución. El preprocesador es anterior al tiempo de compilación, pero debemos aclararlo

Este artículo de blog muestra ¿Cómo detectar el simulador de iPhone? claramente

Tiempo de ejecución

En primer lugar, discutamos brevemente. UIDevice le proporciona información sobre el dispositivo.

[[UIDevice currentDevice] model]

le devolverá "iPhone Simulator" o "iPhone" de acuerdo con el lugar donde se ejecuta la aplicación.

Tiempo de compilación

Sin embargo, lo que desea es utilizar el tiempo de compilación definido. ¿Por qué? Porque compila su aplicación estrictamente para que se ejecute dentro del Simulador o en el dispositivo. Apple hace un llamado definido TARGET_IPHONE_SIMULATOR. Así que echemos un vistazo al código:

#if TARGET_IPHONE_SIMULATOR

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

#endif
onmyway133
fuente
1
¿Cómo mejora esto en otras respuestas?
mmmmmm
@ Mark Se aclara un poco
onmyway133
55
Actualmente, en Xcode 7, iOS 9 Simulator [[UIDevice currentDevice] model]regresa iPhonetambién en lugar de iPhone Simulator. Entonces, creo que este no es el mejor enfoque.
eMdOS el
6

Las respuestas anteriores están un poco anticuadas. Descubrí que todo lo que necesita hacer es consultar la TARGET_IPHONE_SIMULATORmacro ( no es necesario incluir ningún otro archivo de encabezado [suponiendo que esté codificando para iOS]).

Intenté TARGET_OS_IPHONEpero devolvió el mismo valor (1) cuando se ejecuta en un dispositivo y simulador real, por eso recomiendo usar en su TARGET_IPHONE_SIMULATORlugar.

Persona maravillosa
fuente
TARGET_OS_IPHONE es para el código que podría ejecutarse en iOS o en MacOS X. Obviamente, querrá que ese código se comporte como "iPhone" en un simulador.
gnasher729
4

Tuve el mismo problema, ambos TARGET_IPHONE_SIMULATORy TARGET_OS_IPHONEsiempre están definidos, y están configurados en 1. La solución de Pete funciona, por supuesto, pero si alguna vez se basa en algo que no sea Intel (poco probable, pero quién sabe), aquí hay algo que es seguro. siempre y cuando el hardware del iPhone no cambie (por lo que su código siempre funcionará para los iphones actualmente disponibles):

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

Ponga eso en un lugar conveniente, y luego pretenda que las TARGET_*constantes se definieron correctamente.


fuente
4

¿Alguien ha considerado la respuesta proporcionada aquí ?

Supongo que el objetivo-c equivalente sería

+ (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
fuente
4

Para Swift 4.2 / xCode 10

Creé una extensión en UIDevice, por lo que puedo preguntar fácilmente si el simulador se está ejecutando.

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

En mi AppDelegate, por ejemplo, uso este método para decidir si es necesario registrarse para la notificación remota, lo que no es posible para el simulador.

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

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

Para incluir todos los tipos de "simuladores"

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}
jeffr
fuente
44
No tiene nada que ver con Xcode 7. Si ejecuta iOS Simulator con iOS8 (desde Xcode 7), esto funcionará. No funcionará para iOS9 donde [[UIDevice currentDevice] model] solo devuelve "iPhone" si la aplicación se lanzó desde iOS Simulator
Stefan
¿por qué no -[NSString containsString]?
Gobe
1

Con Swift 4.2 (Xcode 10), podemos hacer esto

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif
iHS
fuente
1
Solo otra copia pegar
J. Doe
0

Mi respuesta se basa en la respuesta de @Daniel Magnusson y los comentarios de @Nuthatch y @ n.Drake. y lo escribo para ahorrar tiempo a los usuarios rápidos que trabajan en iOS9 y en adelante.

Esto es lo que funcionó para mí:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}
euthimis87
fuente
1
El código no funcionará si un usuario agrega Simulatorpalabras en el nombre de su dispositivo
mbelsky
Desafortunadamente, con XCode 8 UIDevice.current.nameinforma el nombre de la máquina en la que se está ejecutando el simulador (generalmente algo así como "MacBook Pro de Simon" ahora), por lo que la prueba se ha vuelto poco confiable. Todavía estoy buscando una forma limpia de solucionarlo.
Michael
0

/// Devuelve verdadero si es un simulador y no un dispositivo

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

Apple ha agregado soporte para verificar que la aplicación esté dirigida al simulador con lo siguiente:

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

si nada funcionó, intente esto

public struct Platform {

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

}
Aklesh Rathaur
fuente
-4

En mi opinión, la respuesta (presentada arriba y repetida abajo):

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

es la mejor respuesta porque obviamente se ejecuta en tiempo de ejecución en lugar de ser una DIRECTIVA DE COMPILACIÓN.

usuario1686700
fuente
11
Estoy en desacuerdo. Este código termina en su producto, mientras que una directiva del compilador mantiene la rutina, innecesaria en el dispositivo.
nueve piedras
1
Las directivas del compilador funcionan porque el dispositivo y los simuladores son objetivos de compilación completamente diferentes, es decir, no usaría el mismo binario en ambos. Se tiene que ser compilado en un hardware diferente, así que tiene sentido en este caso.
Brad Parks
Ser ejecutado en RUNTIME lo convierte en la peor respuesta posible.
gnasher729
-4

Esto funcionó para mí mejor

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


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

}
Mani
fuente
2
En Xcode 7.3, vuelve el iPhone 6 Plus Simulator "iPhone".
Eric