Como determinar programaticamente se meu aplicativo está sendo executado no simulador do iphone?

270

Como a pergunta indica, eu gostaria principalmente de saber se meu código está sendo executado no simulador, mas também estaria interessado em saber a versão específica do iphone que está sendo executada ou simulada.

EDIT: eu adicionei a palavra 'programaticamente' ao nome da pergunta. O objetivo da minha pergunta é ser capaz de incluir / excluir código dinamicamente, dependendo da versão / simulador em execução, então eu realmente procuraria algo como uma diretiva de pré-processador que possa me fornecer essas informações.

Jeffrey Meyer
fonte
Não tenho certeza se uma diretiva de pré-processador é dinâmica (embora possa ser o que você estava procurando de qualquer maneira). A diretiva significa que você realmente sabia, quando a construiu, onde ia acabar funcionando.
WiseOldDuck 15/04

Respostas:

356

Já perguntei, mas com um título muito diferente.

Quais #defines são configuradas pelo Xcode ao compilar para o iPhone

Vou repetir minha resposta a partir daí:

Está nos documentos do SDK em "Compilando código-fonte condicionalmente"

A definição relevante é TARGET_OS_SIMULATOR, definida em /usr/include/TargetConditionals.h na estrutura do iOS. Nas versões anteriores do conjunto de ferramentas, era necessário escrever:

#include "TargetConditionals.h"

mas isso não é mais necessário na cadeia de ferramentas atual (Xcode 6 / iOS8).

Então, por exemplo, se você quiser verificar se está executando no dispositivo, faça

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

dependendo do que for apropriado para o seu caso de uso.

Airsource Ltd
fonte
1
Obrigado. Concordo com você que esta é uma versão mais específica da sua pergunta original. Se a sua tivesse surgido na minha pesquisa original, eu nem precisaria perguntar.
11139 Jeffrey Meyer
5
Tenha cuidado com essas definições. Quando você compila o código com o item de menu 'Projeto> Definir SDK ativo> Simulador ...', como TARGET_IPHONE_SIMULATOR como variáveis ​​TARGET_OS_IPHONE são definidas! Portanto, a única maneira correta de separar a lógica é apontada abaixo por Pete (obrigado, cara).
Vadim
5
Veja a diferença #if e #ifdef. Para mim, foi a causa do comportamento incorreto.
Anton
7
Talvez a necessidade de incluir TargetConditionals tenha sido evitada desde que isso foi escrito, mas só queria observar que #if TARGET_IPHONE_SIMULATOR funciona sem incluir TargetConditionals.h agora.
dmur
1
@Dimitris É uma boa prática. Você não sabe como TARGET_OS_SIMULATOR foi definido, então (TARGET_OS_SIMULATOR) pode não ser idêntico ao TARGET_OS_SIMULATOR!
Airsource Ltd
106

Código atualizado:

Isto é suposto funcionar 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

Postagem original (desde que descontinuada)

Este código informa se você está executando em um simulador.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
Pete
fonte
7
No iOS 8 e no Xcode 6.1.1, o TARGET_OS_IPHONE é verdadeiro no simulador.
malhal
3
isso não worik mais em versões mais recentes XCode
Fabio Napodano
1
A menos que você esteja em 2016 e execute um simulador de 64 bits. Ou em 2019 e execute seu código em um iPhone com processador Intel.
precisa saber é o seguinte
61

Não diretiva pré-processador, mas era isso que eu estava procurando quando cheguei a essa pergunta;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}
Daniel Magnusson
fonte
9
[model compare:iPhoneSimulator] == NSOrderedSamedeve ser escrito como[model isEqualToString:iPhoneSimulator]
user102008 11/11
18
Ou [model hasSuffix:@"Simulator"]se você se importa apenas com o "simulador" em geral, não com o iPhone ou o iPad em particular. Esta resposta não vai funcionar para simulador de iPad :)
Nuthatch
Promovido porque o comentário de Nuthatch faz desta a melhor resposta in toto.
Le Mot Juiced
12
No iOS9, verifique o dispositivo em namevez demodel
n.Drake
1
O código não vai funcionar se um usuário adiciona Simulatorpalavra em seu nome do dispositivo
mbelsky
55

A melhor maneira de fazer isso é:

#if TARGET_IPHONE_SIMULATOR

e não

#ifdef TARGET_IPHONE_SIMULATOR

desde sempre definido: 0 ou 1

Taranfx
fonte
39

HÁ UMA MANEIRA MELHOR AGORA!

A partir do Xcode 9.3 beta 4, você pode usar #if targetEnvironment(simulator)para verificar.

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

A ATUALIZAÇÃO
Xcode 10 e iOS 12 SDK também suporta isso.

Stefan Vasiljevic
fonte
1
Este é o único que funciona para mim, o restante das soluções não funcionou.
Vrutin Rathod
Nota Isso é apenas rápido.
Matt S.
35

No caso do Swift, podemos implementar os seguintes

Podemos criar struct que permite criar dados estruturados

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

Então, se quiséssemos detectar se o aplicativo está sendo criado para o dispositivo ou simulador no Swift, então.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}
Nischal Hada
fonte
Implementação mais limpa na minha opinião, e é responsável pelas arquiteturas x86_64 e i386. Me ajudou a superar um bug estranho de dispositivo versus simulador no Core Data. Você é o cara!
Iron John Bonney
5
No Playground, você receberá um aviso: "Código após 'retorno' nunca será executado". Então eu acho #if #else #endifque será melhor.
DawnSong
12

Trabalhos para Swift 5eXcode 11.3.1

Use este código:

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

Todas essas respostas são boas, mas de alguma forma confunde o novato como eu, pois não esclarece a verificação de compilação e a verificação de tempo de execução. O pré-processador está antes do tempo de compilação, mas devemos deixar mais claro

Este artigo do blog mostra Como detectar o simulador do iPhone? claramente

Tempo de execução

Primeiro de tudo, vamos discutir em breve. O UIDevice já fornece informações sobre o dispositivo

[[UIDevice currentDevice] model]

retornará o "iPhone Simulator" ou "iPhone" de acordo com o local em que o aplicativo está sendo executado.

Tempo de compilação

No entanto, o que você deseja é usar o tempo de compilação definido. Por quê? Porque você compila seu aplicativo estritamente para ser executado dentro do Simulador ou no dispositivo. A Apple faz uma definição chamada TARGET_IPHONE_SIMULATOR. Então, vamos olhar o código:

#if TARGET_IPHONE_SIMULATOR

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

#endif
onmyway133
fonte
1
Como isso melhora em outras respostas?
mmmmmm
@Mark It esclarece um pouco #
onmyway133
5
Atualmente, no Xcode 7, o iOS 9 Simulator também [[UIDevice currentDevice] model]está retornando em iPhonevez de iPhone Simulator. Então, acho que essa não é a melhor abordagem.
eMdOS 12/01
6

As respostas anteriores são um pouco datadas. Descobri que tudo que você precisa fazer é consultar a TARGET_IPHONE_SIMULATORmacro ( não é necessário incluir outros arquivos de cabeçalho [supondo que você esteja codificando para iOS]).

Tentei, TARGET_OS_IPHONEmas ele retornou o mesmo valor (1) ao executar em um dispositivo e simulador reais, é por isso que recomendo o uso TARGET_IPHONE_SIMULATOR.

Stunner
fonte
TARGET_OS_IPHONE é para código que pode ser executado no iOS ou no MacOS X. Obviamente, você deseja que esse código se comporte da maneira "iPhone" em um simulador.
precisa saber é o seguinte
6

Em rápida:

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

Em Detectar se o aplicativo está sendo criado para dispositivo ou simulador no Swift

CedricSoubrie
fonte
Para distinguir entre aplicativos para Mac: #if (arch (i386) || arch (x86_64)) && os (OSX) // estamos em um simulador em execução no mac, e não em um aplicativo para mac. (Para plataformas cruzadas código incluído nas metas de mac)
Bobjt
4

Eu tive o mesmo problema, ambos TARGET_IPHONE_SIMULATORe TARGET_OS_IPHONEsempre definidos, e definido como 1. A solução de Pete funciona, é claro, mas se você desenvolver algo que não seja intel (improvável, mas quem sabe), aqui está algo seguro como desde que o hardware do iphone não seja alterado (portanto, seu código funcionará sempre para os iphones atualmente disponíveis):

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

Coloque isso em algum lugar conveniente e depois finja que as TARGET_*constantes foram definidas corretamente.


fonte
4

Alguém considerou a resposta fornecida aqui ?

Suponho que o objetivo-c equivalente seria

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

Para Swift 4.2 / xCode 10

Criei uma extensão no UIDevice, para poder facilmente perguntar se o simulador está em execução.

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

No meu AppDelegate, por exemplo, uso esse método para decidir se é necessário o registro para notificação remota, o que não é possível para o simulador.

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

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

Para incluir todos os tipos de "simuladores"

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}
jeffr
fonte
4
Não tem nada a ver com o Xcode 7. Se você executar o iOS Simulator com iOS8 (do Xcode 7), isso funcionará. Não vai funcionar para iOS9 onde [[UIDevice currentDevice] modelo] retorna somente "iPhone" se o aplicativo foi lançado do iOS Simulator
Stefan
por que não -[NSString containsString]?
Gobe
1

Com o Swift 4.2 (Xcode 10), podemos fazer isso

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif
iHS
fonte
1
Apenas uma outra cópia colar
J. Doe
0

Minha resposta é baseada na resposta de Daniel Magnusson e nos comentários de @Nuthatch e @ n.Drake. e escrevo para economizar tempo para usuários rápidos que trabalham no iOS9 em diante.

Isto é o que funcionou para mim:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}
euthimis87
fonte
1
O código não vai funcionar se um usuário adiciona Simulatorpalavra em seu nome do dispositivo
mbelsky
Infelizmente, o XCode 8 UIDevice.current.namerelata o nome da máquina em que o Simulador está sendo executado (normalmente algo como "Simon's MacBook Pro" agora), para que o teste não seja confiável. Ainda estou procurando uma maneira limpa de corrigi-lo.
Michael
0

/// Retorna true se seu simulador e não um dispositivo

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

A Apple adicionou suporte para verificar se o aplicativo está direcionado para o simulador com o seguinte:

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

se nada funcionou, tente isso

public struct Platform {

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

}
Aklesh Rathaur
fonte
-4

Na minha opinião, a resposta (apresentada acima e repetida abaixo):

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

é a melhor resposta, pois é obviamente executada em RUNTIME, em vez de ser uma DIRETIVA COMPILE.

user1686700
fonte
11
Discordo. Esse código termina no seu produto, enquanto uma diretiva de compilador mantém a rotina no dispositivo desnecessária.
nine stones
1
As diretivas do compilador funcionam porque o dispositivo e os simuladores são alvos de compilação completamente diferentes - ou seja, você não usaria o mesmo binário em ambos. Ele deve ser compilado em hardware diferente, portanto, faz sentido nesse caso.
Brad Parks
Ser executado em RUNTIME torna a pior resposta possível.
precisa saber é o seguinte
-4

Isso funcionou para mim melhor

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


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

}
Mani
fonte
2
No Xcode 7.3, o iPhone 6 Plus Simulator retorna "iPhone".
Eric