【问题标题】:How can I programmatically determine if my app is running in the iphone simulator?如何以编程方式确定我的应用程序是否在 iphone 模拟器中运行?
【发布时间】:2010-10-02 06:42:38
【问题描述】:

正如问题所述,我主要想知道我的代码是否在模拟器中运行,但也有兴趣了解正在运行或正在模拟的特定 iphone 版本。

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

【问题讨论】:

  • 我不确定预处理器指令是动态的(尽管它可能是您正在寻找的东西)。该指令意味着您实际上知道,当您构建它时,它将在哪里运行。
  • 我知道我的目标只是一个新的 iPhone 或模拟器,我喜欢__x86_64__(iPhone 模拟器)和__arm64__(iPhone 设备)

标签: ios objective-c swift xcode ios-simulator


【解决方案1】:

已经问过了,但标题完全不同。

What #defines are set up by Xcode when compiling for iPhone

我会从那里重复我的答案:

它位于 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

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

【讨论】:

  • 谢谢。我同意你的看法,这是你原来问题的一个更具体的版本。如果你的问题出现在我最初的搜索中,我什至不需要问。
  • 小心这些定义。当您使用菜单项“Project > Set Active SDK > Simulator...”编译代码时,TARGET_IPHONE_SIMULATOR as TARGET_OS_IPHONE 变量都被定义了!因此,Pete(谢谢老兄)在下面指出了分离逻辑的唯一正确方法。
  • 观察#if 和#ifdef 的区别。对我来说,这是错误行为的原因。
  • 也许在编写此代码后就不再需要包含 TargetConditionals,但只是想指出 #if TARGET_IPHONE_SIMULATOR 现在可以在不包含 TargetConditionals.h 的情况下工作。
  • @Dimitris 这是一个很好的做法。您不知道 TARGET_OS_SIMULATOR 是如何定义的,因此 !(TARGET_OS_SIMULATOR) 可能与 !TARGET_OS_SIMULATOR 不同
【解决方案2】:

更新代码:

据称这是正式的工作。

#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

【讨论】:

  • 从 iOS 8 和 Xcode 6.1.1 开始,模拟器上的 TARGET_OS_IPHONE 为 true。
  • 这在较新的 XCode 版本上不再适用
  • 除非你在 2016 年并且运行 64 位模拟器。或者在 2019 年在配备英特尔处理器的 iPhone 上运行您的代码。
【解决方案3】:

不是预处理器指令,但这是我遇到这个问题时正在寻找的;

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

【讨论】:

  • [model compare:iPhoneSimulator] == NSOrderedSame 应该写成[model isEqualToString:iPhoneSimulator]
  • [model hasSuffix:@"Simulator"],如果您只关心一般的“模拟器”,而不是特别关心 iPhoneiPad。这个答案不适用于 iPad 模拟器 :)
  • 投了赞成票,因为 Nuthatch 的评论使它成为最佳答案。
  • 在iOS9中,检查设备name而不是model
  • 如果用户在其设备名称中添加Simulator 字样,该代码将不起作用
【解决方案4】:

最好的方法是:

#if TARGET_IPHONE_SIMULATOR

而不是

#ifdef TARGET_IPHONE_SIMULATOR

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

【讨论】:

    【解决方案5】:

    现在有更好的方法!

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

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

    更新
    Xcode 10 和 iOS 12 SDK 也支持这个。

    【讨论】:

    • 这是唯一对我有用的,其他解决方案都不起作用。
    • 注意这只在swift中。
    【解决方案6】:

    如果是 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 中一个奇怪的设备与模拟器错误。你就是男人!
    • 在 Playground 中,您会收到一条警告,“'return' 之后的代码将永远不会被执行”。所以我觉得#if #else #endif会更好。
    【解决方案7】:

    适用于 Swift 5Xcode 12

    使用此代码:

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

    【讨论】:

      【解决方案8】:

      所有这些答案都很好,但它以某种方式使像我这样的新手感到困惑,因为它没有阐明编译检查和运行时检查。预处理器在编译时之前,但我们应该更清楚

      这篇博文清楚地显示了How to detect the iPhone simulator?

      运行时

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

      [[UIDevice currentDevice] model]
      

      将根据应用运行的位置返回“iPhone Simulator”或“iPhone”。

      编译时间

      但是你想要的是使用编译时间定义。为什么?因为您严格编译您的应用程序以在模拟器内或设备上运行。 Apple 定义了一个名为TARGET_IPHONE_SIMULATOR 的定义。那么让我们看一下代码:

      #if TARGET_IPHONE_SIMULATOR
      
      NSLog(@"Running in Simulator - no app store or giro");
      
      #endif
      

      【讨论】:

      • 这对其他答案有何改进?
      • @Mark 它澄清了一点
      • 目前,在 Xcode 7 中,iOS 9 Simulator [[UIDevice currentDevice] model] 也返回 iPhone 而不是 iPhone Simulator。所以,我认为这不是最好的方法。
      【解决方案9】:

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

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

      【讨论】:

      • TARGET_OS_IPHONE 用于可能在 iOS 或 MacOS X 上运行的代码。显然,您希望该代码在模拟器上以“iPhone”方式运行。
      【解决方案10】:

      迅速:

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

      来自Detect if app is being built for device or simulator in Swift

      【讨论】:

      • 区分mac应用:#if (arch(i386)||arch(x86_64))&&!os(OSX)//我们是在mac上运行的模拟器,而不是mac应用程序。 (对于 mac 目标中包含的跨平台代码)
      【解决方案11】:

      有人考虑过here提供的答案吗?

      我想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);
          }
      }
      

      【讨论】:

        【解决方案12】:

        适用于 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()
        }
        

        【讨论】:

          【解决方案13】:

          我遇到了同样的问题,TARGET_IPHONE_SIMULATORTARGET_OS_IPHONE 总是被定义,并设置为 1。当然,Pete 的解决方案是有效的,但如果你碰巧建立在 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_* 常量定义正确。

          【讨论】:

            【解决方案14】:

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

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

            【讨论】:

            • 它与 Xcode 7 无关。如果您使用 iOS8(来自 Xcode 7)运行 iOS Simulator,那么这将起作用。如果应用程序是从 iOS 模拟器启动的,它不适用于 [[UIDevice currentDevice] model] 仅返回“iPhone”的 iOS9
            • 为什么不-[NSString containsString]
            【解决方案15】:

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

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

            【讨论】:

            • 只是另一个复制粘贴
            【解决方案16】:

            我的答案基于@Daniel Magnusson 的答案以及@Nuthatch 和@n.Drake 的cmets。我写它是为了为使用 iOS9 及更高版本的 swift 用户节省一些时间。

            这对我有用:

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

            【讨论】:

            • 如果用户在其设备名称中添加Simulator 字样,该代码将不起作用
            • 不幸的是,XCode 8 UIDevice.current.name 报告了模拟器正在运行的机器的名称(现在通常类似于“Simon 的 MacBook Pro”),因此测试变得不可靠。我仍在寻找一种干净的方法来解决它。
            【解决方案17】:

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

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

            【讨论】:

              【解决方案18】:

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

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

              【讨论】:

                【解决方案19】:

                如果没有任何效果,试试这个

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

                【讨论】:

                  【解决方案20】:

                  这对我最有效

                  NSString *name = [[UIDevice currentDevice] name];
                  
                  
                  if ([name isEqualToString:@"iPhone Simulator"]) {
                  
                  }
                  

                  【讨论】:

                  • 在 Xcode 7.3 上,iPhone 6 Plus 模拟器返回 "iPhone"
                  【解决方案21】:

                  在我看来,答案(上面提出并在下面重复):

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

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

                  【讨论】:

                  • 我不同意。此代码最终会出现在您的产品中,而编译器指令将 - 在设备上不必要的 - 例程排除在外。
                  • 编译器指令起作用是因为设备和模拟器是完全不同的编译目标——即你不会在两者上使用相同的二进制文件。它必须编译到不同的硬件,所以在这种情况下是有意义的。
                  • 在 RUNTIME 执行使其成为最差可能的答案。
                  猜你喜欢
                  • 2011-03-02
                  • 1970-01-01
                  • 2011-10-17
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-08-12
                  • 2012-03-26
                  相关资源
                  最近更新 更多