Определить, если приложение создается для устройства или симулятора в Swift



в Objective-C мы можем узнать, создается ли приложение для устройства или симулятора с помощью макросов:



#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif


это макросы времени компиляции и недоступны во время выполнения.



как я могу достичь того же в Swift? Я искал переполнение стека, заглянул в документы и не могу понять это.

605   15  

15 ответов:

обновление 14/09/17

хотя этот ответ может работать, рекомендуемое решение для статической проверки (как пояснили несколько инженеров Apple) заключается в определении пользовательского флага компилятора, предназначенного для симуляторов iOS. Для получения подробных инструкций о том, как это сделать, см. @mbelsky это.

оригинальный ответ

Если вам нужна статическая проверка (например, не во время выполнения if / else), вы не можете обнаружить симулятор напрямую, но вы можете обнаружить iOS на рабочем столе архитектура, как следует

#if (arch(i386) || arch(x86_64)) && os(iOS)
    ...
#endif

очевидно, что это ложь на устройстве, но она возвращает true для симулятора iOS, как указано в документация:

конфигурация сборки arch(i386) возвращает true при компиляции кода для 32–разрядного симулятора iOS.

если вы разрабатываете для симулятора, отличного от iOS, вы можете просто изменить

обновленная информация по состоянию на 20 февраля 2018 года

похоже, что у @russbishop есть авторитетный ответ, который делает этот ответ "неправильным", хотя он, похоже, работал в течение длительного времени.

определить, если приложение строится для устройства или симулятора в Swift

Предыдущий Ответ

основываясь на ответе @WZW и комментариях @Pang, я создал простую структуру утилиты. Это решение позволяет избежать предупреждения произведено ответом @WZW.

import Foundation

struct Platform {

    static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0
    }

}

пример использования:

if Platform.isSimulator {
    print("Running on Simulator")
}

УСТАРЕЛ ДЛЯ SWIFT 4.1. использовать #if targetEnvironment(simulator) вместо. источник

для обнаружения симулятора в Swift вы можете использовать конфигурацию сборки:

  • определите эта конфигурация - D IOS_SIMULATOR на Компилятор SWIFT - Пользовательских Флагов > Прочие Флаги Свифт
  • выберите любой iOS симулятор SDK в выпадающем Drop down list

Теперь вы можете использовать этот заявление для обнаружения тренажера:

#if IOS_SIMULATOR
    print("It's an iOS Simulator")
#else
    print("It's a device")
#endif

также вы можете расширить класс UIDevice:

extension UIDevice {
    var isSimulator: Bool {
        #if IOS_SIMULATOR
            return true
        #else
            return false
        #endif
    }
}
// Example of usage: UIDevice.current.isSimulator

От Xcode 9.3

#if targetEnvironment(simulator)

Swift поддерживает новое условие платформы targetEnvironment с a один допустимый аргумент симулятор. Условная компиляция формы "#if targetEnvironment (simulator) " теперь можно использовать для определения того, когда цель сборки является симулятором. Компилятор Swift попытается обнаружьте, предупредите, и предложите пользу targetEnvironment (имитатора) когда оценка условий платформы, которые, по-видимому, тестируются для симулятора среды косвенно, через существующую платформу os () и arch () условия. (SE-0190)

iOS 9+:

extension UIDevice {
    static var isSimulator: Bool {
        return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}

Swift 3:

extension UIDevice {
    static var isSimulator: Bool {
        return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
    }
}

перед iOS 9:

extension UIDevice {
    static var isSimulator: Bool {
        return UIDevice.currentDevice().model == "iPhone Simulator"
    }
}

Цель-C:

@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

Swift 4

теперь вы можете использовать targetEnvironment(simulator) в качестве аргумента.

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

обновлено для Xcode 9.3

позвольте мне прояснить некоторые вещи здесь:

  1. TARGET_OS_SIMULATOR во многих случаях не устанавливается в Swift-коде; вы можете случайно получить его импортированный из-за заголовка моста, но это хрупко и не поддерживается. Это также не возможно даже в рамках. Вот почему некоторые люди путают о том, работает ли это в Swift.
  2. я настоятельно рекомендую не использовать архитектуру в качестве замены симулятора.

для выполнения динамических чеки:

проверка ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil это прекрасно.

вы также можете получить базовую модель моделируется путем проверки SIMULATOR_MODEL_IDENTIFIER, который будет возвращать строки, как iPhone10,3.

для выполнения статических проверок:

Xcode 9.2 & earlier: определите свой собственный флаг компиляции Swift (как показано в других ответах).

Xcode 9.3 + используйте новое условие targetEnvironment:

#if targetEnvironment(simulator)
    // for sim only
#else
    // for device
#endif

что работает для меня, так как Swift 1.0 проверяет архитектуру, отличную от arm:

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

     //simulator
#else 
     //device

#endif

во время выполнения, но проще, чем большинство других решений здесь:

if TARGET_OS_SIMULATOR != 0 {
    // target is current running in the simulator
}

кроме того, вы можете просто вызвать вспомогательную функцию Objective-C, которая возвращает логическое значение, которое использует макрос препроцессора (особенно если вы уже смешиваете в своем проекте).

Edit: не лучшее решение, особенно с Xcode 9.3. Смотрите ответ Хотджарда

в современных системах:

#if targetEnvironment(simulator)
    // sim
#else
    // device
#endif

это очень просто.

TARGET_IPHONE_SIMULATOR является устаревшим в iOS 9. TARGET_OS_SIMULATOR замена. Также TARGET_OS_EMBEDDED доступно.

С TargetConditionals.h:

#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 */ 

в Xcode 7.2 (и ранее, но я не проверял, насколько раньше) вы можете установить флаг сборки для конкретной платформы "-D TARGET_IPHONE_SIMULATOR" для "любого симулятора iOS".

посмотрите в настройках сборки проекта в разделе "Swift Compiler-Customer Flags", а затем установите флаг в разделе"другие флаги Swift". Вы можете установить флаг конкретной платформы, нажав на значок "плюс" при наведении указателя мыши на конфигурацию сборки.

есть несколько преимуществ сделать это таким образом: 1) Вы можно использовать один и тот же условный тест ("#if TARGET_IPHONE_SIMULATOR") в коде Swift и Objective-C. 2) Вы можете скомпилировать переменные, которые применяются только к каждой сборке.

скриншот настроек сборки Xcode

все описано здесь Дарвин.TargetConditionals: https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h

TARGET_OS_SIMULATOR - Generated code will run under a simulator

я использовал этот код в Swift 3

if TARGET_IPHONE_SIMULATOR == 1 {
    //simulator
} else {
    //device
}

Swift 4:

В настоящее время я предпочитаю использовать ProcessInfo класс, чтобы узнать, является ли устройство симулятором и какое устройство используется:

if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
            print("yes is a simulator :\(simModelCode)")
}

но, как вы знаете, simModelCode это не удобный код, чтобы сразу понять, какой тип симулятора был запущен, поэтому, если вам нужно, вы можете попробовать увидеть этот другой SO ответ чтобы определить текущую модель iPhone / устройства и иметь более удобочитаемую строку.

используйте этот код ниже:

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

работает Swift 4 и Xcode 9.4.1

Comments

    Ничего не найдено.