Detect if app is being built for device or simulator in Swift
在Objective-C中,我们可以知道是否正在为使用宏的设备或模拟器构建应用程序:
1 2 3 4 5 | #if TARGET_IPHONE_SIMULATOR // Simulator #else // Device #endif |
这些是编译时宏,在运行时不可用。
我怎样才能在斯威夫特做到这一点?我搜索了堆栈溢出,查看了文档,但找不到它。
更新30/01/19
虽然这个答案可能有效,但静态检查的建议解决方案(如几个苹果工程师所阐明的)是定义一个针对iOS模拟器的自定义编译器标志。有关如何处理的详细说明,请参阅@mbelsky的答案。
原始答案如果需要静态检查(例如,不是运行时if/else),则无法直接检测模拟器,但可以在桌面架构上检测iOS,如下所示
1 2 3 | #if (arch(i386) || arch(x86_64)) && os(iOS) ... #endif |
在Swift 4.1版本之后
Latest use, now directly for all in one condition for all types of simulators need to apply only one condition -
1 2 3 4 5 | #if targetEnvironment(simulator) // your simulator code #else // your real device code #endif |
如需更多说明,您可以查看SWIFT建议书SE-0190。
For older version -
显然,这在设备上是错误的,但对于iOS模拟器,它返回true,如文档中指定的那样:
The arch(i386) build configuration returns true when the code is compiled for the 32–bit iOS simulator.
如果您是为除iOS之外的模拟器开发的,您可以简单地改变
检测watchos模拟器
1 2 3 | #if (arch(i386) || arch(x86_64)) && os(watchOS) ... #endif |
检测TVOS模拟器
1 2 3 | #if (arch(i386) || arch(x86_64)) && os(tvOS) ... #endif |
或者,甚至,检测任何模拟器
1 2 3 | #if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS)) ... #endif |
如果运行时检查没有问题,可以检查iOS 8及以下版本中的
请注意,这与使用预处理器标志相比有所不同,而且有一些限制。例如,如果
例如,假设您希望在设备和模拟器上有不同的导入。这对于动态检查是不可能的,而对于静态检查则是微不足道的。
1 2 3 4 5 | #if (arch(i386) || arch(x86_64)) && os(iOS) import Foo #else import Bar #endif |
另外,由于Swift预处理器将标志替换为
要解决此警告,请参阅其他答案之一。
已过时的Swift 4.1。用
要在swift中检测模拟器,可以使用构建配置:
- 在swift编译器-自定义标志>其他swift标志中定义此配置-d ios_模拟器
- 在此下拉菜单中选择任何iOS模拟器SDK
现在您可以使用此语句检测模拟器:
1 2 3 4 5 | #if IOS_SIMULATOR print("It's an iOS Simulator") #else print("It's a device") #endif |
还可以扩展uidevice类:
1 2 3 4 5 6 7 8 9 10 | extension UIDevice { var isSimulator: Bool { #if IOS_SIMULATOR return true #else return false #endif } } // Example of usage: UIDevice.current.isSimulator |
更新信息截止2018年2月20日
看起来@russbishop有一个权威的答案,使得这个答案"不正确"——尽管它看起来工作了很长时间。
在swift中检测是否正在为设备或模拟器构建应用程序
先前的答案
基于@wzw的回答和@pang的评论,我创建了一个简单的实用工具结构。此解决方案可避免@wzw的回答产生警告。
1 2 3 4 5 6 7 8 9 | import Foundation struct Platform { static var isSimulator: Bool { return TARGET_OS_SIMULATOR != 0 } } |
示例用法:
1 2 3 | if Platform.isSimulator { print("Running on Simulator") } |
从XCODE 9.3
1 | #if targetEnvironment(simulator) |
Swift supports a new platform condition targetEnvironment with a
single valid argument simulator. Conditional compilation of the form
'#if targetEnvironment(simulator)' can now be used to detect when the build target is a simulator. The Swift compiler will attempt to
detect, warn, and suggest the use of targetEnvironment(simulator) when
evaluating platform conditions that appear to be testing for simulator
environments indirectly, via the existing os() and arch() platform
conditions. (SE-0190)
IOS 9 +:
1 2 3 4 5 | extension UIDevice { static var isSimulator: Bool { return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil } } |
斯威夫特3:
1 2 3 4 5 | extension UIDevice { static var isSimulator: Bool { return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil } } |
在iOS 9之前:
1 2 3 4 5 | extension UIDevice { static var isSimulator: Bool { return UIDevice.currentDevice().model =="iPhone Simulator" } } |
ObjultC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @interface UIDevice (Additions) - (BOOL)isSimulator; @end @implementation UIDevice (Additions) - (BOOL)isSimulator { if([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9, 0, 0}]) { return [NSProcessInfo processInfo].environment[@"SIMULATOR_DEVICE_NAME"] != nil; } else { return [[self model] isEqualToString:@"iPhone Simulator"]; } } @end |
斯威夫特4
你现在可以用
1 2 3 4 5 | #if targetEnvironment(simulator) // Simulator #else // Device #endif |
更新Xcode 9.3
让我在这里澄清一些事情:
要执行动态检查:
检查
您还可以通过检查
要执行静态检查:
xcode 9.2&early:定义自己的swift编译标志(如其他答案所示)。
xcode 9.3+使用新的targetEnvironment条件:
1 2 3 4 5 | #if targetEnvironment(simulator) // for sim only #else // for device #endif |
自Swift 1.0以来,我的工作是检查除ARM之外的架构:
1 2 3 4 5 6 7 | #if arch(i386) || arch(x86_64) //simulator #else //device #endif |
运行时,但比其他大多数解决方案更简单:
1 2 3 | if TARGET_OS_SIMULATOR != 0 { // target is current running in the simulator } |
或者,您可以调用一个Objective-C助手函数,该函数返回一个使用预处理器宏的布尔值(尤其是在项目中已经混合的情况下)。
编辑:不是最好的解决方案,特别是Xcode9.3。看霍贾德的回答
在现代系统中:
1 2 3 4 5 | #if targetEnvironment(simulator) // sim #else // device #endif |
这很容易。
iOS 9中不推荐使用
从targetconditionals.h:
1
2
3
4
5
6 #if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
. . .
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 1
#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
在Xcode7.2中(以及更早的版本,但我还没有测试多久),您可以为"任何iOS模拟器"设置特定于平台的构建标志"-d target_iphone_模拟器"。
在"Swift编译器-客户标志"下查看项目构建设置,然后在"其他Swift标志"中设置标志。当您将鼠标悬停在构建配置上时,可以通过单击"加号"图标来设置特定于平台的标志。
这样做有两个好处:1)你可以在你的Swift和Objective-C代码中使用相同的条件测试("如果目标是iPhone模拟器")。2)您可以编译只适用于每个构建的变量。
xcode生成设置屏幕截图
这里描述的都是达尔文。目标条件:http://GITHUB.COM/Apple / SWIFT CORILBS基金会/ BLB/MUST/CoreFoundation /BASE.子PROJ/SWIFTUNUNTIME/TAIN条件:H
我希望这个分机很方便
1 2 3 4 5 6 7 8 9 | extension UIDevice { static var isSimulator: Bool = { var isSimulator = false #if targetEnvironment(simulator) isSimulator = true #endif return isSimulator }() } |
用途:
1 2 3 | if UIDevice.isSimulator { print("running on simulator") } |
斯威夫特4:
目前,我更喜欢使用processinfo类来了解设备是否是模拟器,以及使用的是哪种设备:
1 2 3 | if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { print("yes is a simulator :\(simModelCode)") } |
但是,正如你所知,
我在swift 3中使用了下面的代码
1 2 3 4 5 | if TARGET_IPHONE_SIMULATOR == 1 { //simulator } else { //device } |
使用以下代码:
1 2 3 4 5 | #if targetEnvironment(simulator) // Simulator #else // Device #endif |
为