如何以编程方式确定我的应用程序是否正在iphone模拟器中运行?


270

正如问题所指出的那样,我主要想知道我的代码是否正在模拟器中运行,但也想知道正在运行或正在模拟的特定iphone版本。

编辑:我在问题名称中添加了“以编程方式”一词。我的问题的关键是能够根据正在运行的版本/模拟器动态地包含/排除代码,因此我真的在寻找可以提供此信息的类似预处理程序指令的东西。


我不确定预处理器指令是否是动态的(尽管无论如何它都可能是您正在寻找的)。该指令意味着您实际上在构建它时就知道它将在哪里运行。
WiseOldDuck

Answers:


356

已经问过,但标题却大不相同。

为iPhone编译时Xcode设置了什么#define

我将从那里重复我的回答:

在SDK文档的“有条件地编译源代码”下

相关定义是TARGET_OS_SIMULATOR,该定义在iOS框架的/usr/include/TargetConditionals.h中定义。在较早版本的工具链上,您必须编写:

#include "TargetConditionals.h"

但这在当前(Xcode 6 / iOS8)工具链上不再需要。

因此,例如,如果要检查设备是否正在运行,则应执行

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

取决于哪个适合您的用例。


1
谢谢。我同意您的意见,这是您原始问题的一个更具体的版本。如果您的搜索出现在我的原始搜索中,我什至不需要询问。
杰弗里·梅耶

5
请谨慎使用这些定义。当使用菜单项“项目>设置活动SDK>仿真器...”编译代码时,作为TARGET_IPHONE_SIMULATOR和TARGET_OS_IPHONE的变量都已定义!因此,皮特(Thanks dude)指出了分离逻辑的唯一正确方法。
Vadim

5
注意#if和#ifdef的区别。对我来说,这是错误行为的原因。
安东2010年

7
自编写此文档以来,也许已消除了包含TargetConditionals的需要,但只想注意#if TARGET_IPHONE_SIMULATOR现在可以不包含TargetConditionals.h而工作。
dmur

1
@Dimitris这是一个好习惯。您不知道TARGET_OS_SIMULATOR的定义方式,所以!(TARGET_OS_SIMULATOR)可能与!TARGET_OS_SIMULATOR不同
Airsource Ltd

106

更新的代码:

据称这是正式工作。

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

原始帖子(已弃用)

此代码将告诉您是否正在模拟器中运行。

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

7
从iOS 8和Xcode 6.1.1开始,TARGET_OS_IPHONE在模拟器上为true。
malhal 2015年

3
这不再适用于较新的XCode版本
Fabio Napodano

1
除非您在2016年并且运行64位模拟器。或者在2019年,在具有Intel处理器的iPhone上运行代码。
gnasher729

61

不是预处理程序指令,但这是我遇到这个问题时要寻找的东西。

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

9
[model compare:iPhoneSimulator] == NSOrderedSame应该写为[model isEqualToString:iPhoneSimulator]
user102008 2011年

18
或者,[model hasSuffix:@"Simulator"]如果您只关心一般的“模拟器”,而不关心iPhoneiPad特别。此答案不适用于iPad模拟器:)
Nuthatch 2014年

由于Nuthatch的评论使这成为最好的答案,因此被推荐。
Le Mot Juiced 2015年

12
在iOS9中,检查设备 name而不要model
Dr.Drake

1
如果用户添加该代码将无法正常工作 Simulator在自己的设备名称字
mbelsky

55

最好的方法是:

#if TARGET_IPHONE_SIMULATOR

并不是

#ifdef TARGET_IPHONE_SIMULATOR

因为它总是被定义:0或1


39

现在有更好的方法!

从Xcode 9.3 beta 4开始,您可以使用#if targetEnvironment(simulator)进行检查。

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

UPDATE
Xcode 10和iOS 12 SDK也支持此功能。


1
这是唯一对我有效的解决方案,其余解决方案均无效。
Vrutin Rathod

注意这只是迅速。
马特·S。

35

在Swift的情况下,我们可以实现以下

我们可以创建允许您创建结构化数据的结构

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

然后,如果我们想检测Swift中是否正在为设备或模拟器构建应用程序,则。

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

我认为这是最干净的实现,它说明了x86_64和i386体系结构。帮助我克服了Core Data中奇怪的设备与模拟器错误。你是男人!
约翰·邦尼

5
在Playground中,您将收到一条警告:“'返回'后的代码将永远不会执行”。所以我认为#if #else #endif会更好。
DawnSong

12

适用于Swift 5Xcode 11.3.1

使用此代码:

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

9

所有这些答案都是好的,但是由于它并不能澄清编译检查和运行时检查,因此它使我这样的新手感到困惑。预处理程序早于编译时间,但我们应该使其更清晰

这篇博客文章显示了如何检测iPhone模拟器?清楚地

运行

首先,让我们简短地讨论一下。UIDevice已为您提供有关设备的信息

[[UIDevice currentDevice] model]

会根据应用程序的运行位置返回“ iPhone模拟器”或“ iPhone”。

编译时间

但是,您要使用的是编译时定义。为什么?因为您严格编译应用程序以使其可以在模拟器内部或设备上运行。苹果公司将其定义为 TARGET_IPHONE_SIMULATOR。因此,让我们看一下代码:

#if TARGET_IPHONE_SIMULATOR

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

#endif

1
这如何改善其他答案?
user151019 2014年

@Mark澄清了一点
onmyway133 2014年

5
当前,在Xcode 7中,iOS 9 Simulator [[UIDevice currentDevice] model]也将返回iPhone而不是iPhone Simulator。因此,我认为这不是最佳方法。
eMdOS

6

先前的答案有些过时。我发现您需要做的就是查询TARGET_IPHONE_SIMULATOR宏(无需包含任何其他头文件(假设您正在为iOS编写代码))。

我尝试过,TARGET_OS_IPHONE但是在实际的设备和模拟器上运行时它返回了相同的值(1),这就是为什么我建议改用它的原因TARGET_IPHONE_SIMULATOR


TARGET_OS_IPHONE用于可能在iOS或MacOS X上运行的代码。显然,您希望该代码在模拟器上表现为“ iPhone”方式。
gnasher729


4

我有同样的问题,无论是TARGET_IPHONE_SIMULATORTARGET_OS_IPHONE总是定义,并设置为1。皮特的解决方案作品,当然,但如果你曾经发生的基础上比Intel以外的东西(不太可能,但谁知道),这里的东西是安全的,因为只要iphone硬件没有变化(因此您的代码将始终适用于当前在那里的iphone):

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

将其放在方便的位置,然后假装TARGET_*常量定义正确。


4

有没有人考虑过这里提供的答案?

我想与Objective-C等效

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

对于Swift 4.2 / xCode 10

我在UIDevice上创建了一个扩展,因此我可以轻松地询问模拟器是否正在运行。

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

例如,在我的AppDelegate中,我使用此方法来确定是否需要注册远程通知,这对于模拟器是不可能的。

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

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

1

包括所有类型的“模拟器”

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

4
它与Xcode 7无关。如果在iOS8上运行iOS Simulator(从Xcode 7开始),则可以使用它。在iOS9上,[[UIDevice currentDevice]模型]仅从iOS模拟器
tesla

为什么不-[NSString containsString]呢?
戈贝(Gobe)

1

使用Swift 4.2(Xcode 10),我们可以做到这一点

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

1
只是另一个复制粘贴
J. Doe

0

我的答案基于@Daniel Magnusson的答案以及@Nuthatch和@ n.Drake的评论。我编写它的目的是为在iOS9及更高版本上工作的迅速用户节省一些时间。

这对我有用:

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

1
如果用户添加的代码将无法正常工作Simulator在自己的设备名称字
mbelsky

不幸的是,由于XCode 8 UIDevice.current.name报告了运行模拟器的计算机的名称(现在通常是类似于“ Simon的MacBook Pro”之类的名称),因此测试变得不可靠。我仍在寻找一种干净的方法来修复它。
迈克尔

0

///如果其模拟器而不是设备,则返回true

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

0

Apple通过以下方式增加了对检查应用程序是否针对模拟器的支持:

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


-4

我认为,答案(在上方显示并在下方重复):

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

是最佳答案,因为它显然是在运行时执行的,而不是作为编译指令的。


11
我不同意。该代码最终出现在您的产品中,而编译器指令将-不需要在设备上的例程排除在外。
九块石头,

1
编译器指令之所以起作用,是因为设备和模拟器是完全不同的编译目标-即,您不会在两者上使用相同的二进制文件。它具有被编译到不同的硬件,因此是很有意义在这种情况下。
布拉德·帕克斯

在RUNTIME执行将使其成为最糟糕的答案。
gnasher729

-4

这对我最好

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


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

}

2
在Xcode 7.3上,iPhone 6 Plus Simulator返回"iPhone"
埃里克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.