programing

Swift에서 앱이 장치 또는 시뮬레이터용으로 구축되어 있는지 여부를 감지하는 방법

lovejava 2023. 4. 14. 20:53

Swift에서 앱이 장치 또는 시뮬레이터용으로 구축되어 있는지 여부를 감지하는 방법

Objective-C에서는 매크로를 사용하여 앱이 디바이스용인지 시뮬레이터용인지를 알 수 있습니다.

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

이것들은 컴파일 시 매크로이며 실행 시 사용할 수 없습니다.

Swift에서도 어떻게 같은 일을 할 수 있을까요?

업데이트 30/01/19

이 답변은 효과가 있을 수 있지만 (여러 Apple 엔지니어에 의해 명확하게 설명되었듯이) 정적 체크를 위해 권장되는 솔루션은 iOS Simulators를 대상으로 한 커스텀 컴파일러 플래그를 정의하는 것입니다.자세한 방법은 @mbelsky의 답변을 참조하십시오.

원답

정적 체크가 필요한 경우(예를 들어 런타임 if/else가 아님) 시뮬레이터를 직접 검출할 수는 없지만 다음과 같은 데스크톱 아키텍처에서 iOS를 검출할 수 있습니다.

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

Swift 4.1 버전 이후

모든 유형의 시뮬레이터에 대해 한 가지 조건에서 직접 사용하는 최신 사용에서는 한 가지 조건만 적용하면 됩니다.

#if targetEnvironment(simulator)
  // your simulator code
#else
  // your real device code
#endif

자세한 내용은 Swift 제안서 SE-0190참조하십시오.


이전 버전의 경우 -

이것은 디바이스에서는 false이지만, 설명서에 기재되어 있듯이 iOS Simulator에서는 true가 반환됩니다.

arch(i386) 빌드 구성은 코드가 32비트 iOS 시뮬레이터용으로 컴파일되면 true를 반환합니다.

중인 iOS를 할 수 .os★★★★★★★★★★★★★★★★★★

시계를 검출하다OS 시뮬레이터

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

TVOS 시뮬레이터를 검출하다

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

또는 시뮬레이터를 검출할 수도 있습니다.

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

시 체크에 가 없는 는, 「 」를 할 수 있습니다.」를 할 수 있습니다.TARGET_OS_SIMULATOR "변수")TARGET_IPHONE_SIMULATOR8버전)은입니다. (iOS 8은 truthy).

이것은 프리프로세서 플래그를 사용하는 것과는 다르며 조금 더 제한적이라는 점에 유의하시기 바랍니다., 예, 이, 이, 이, 이, 이, 이, 습, 습, 습, for, for, for, for, for, for, for, for, for, for, for, for, for, for,if/else구문적으로 유효하지 않습니다(예를 들어 기능 범위 외).

예를 들어, 디바이스와 시뮬레이터에서 다른 Import를 할 수 있습니다.이것은 동적 검사에서는 불가능하지만 정적 검사에서는 사소한 것입니다.

#if (arch(i386) || arch(x86_64)) && os(iOS)
  import Foo
#else
  import Bar
#endif

also also also 로 바뀌기 0 ★★★1preprocessor에서 swift preprocessor에 if/else도달 불능 코드에 대한 경고를 컴파일러가 발생시키는 식입니다.

이 경고를 회피하려면 다른 답변 중 하나를 참조하십시오.

SWIFT 4.1에는 구식입니다.사용하다#if targetEnvironment(simulator)대신.출처

Swift에서 시뮬레이터를 감지하려면 빌드 구성을 사용할 수 있습니다.

  • Swift 컴파일러에서 D IOS_SIMATOR 설정을 정의합니다(커스텀플래그> 기타 Swift 플래그).
  • 이 드롭다운에서 iOS Simulator SDK를 선택합니다.

이제 시뮬레이터를 검출하기 위해 다음 문을 사용할 수 있습니다.

#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

2018년 2월 20일자로 갱신된 정보

@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")
}

스위프트 4

해서 '어울리지 않다'를 할 수 되었습니다.targetEnvironment(simulator)의론으로서.

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

Xcode 9.3용으로 업데이트됨

Xcode 9.3부터

#if targetEnvironment(simulator)

Swift는 하나의 유효한 인수 시뮬레이터를 사용하여 새로운 플랫폼 조건 targetEnvironment를 지원합니다.빌드 대상이 시뮬레이터인 경우를 감지하기 위해 '#if targetEnvironment(시뮬레이터)' 형식의 조건부 컴파일을 사용할 수 있습니다.Swift 컴파일러는 기존 os() 및 arch() 플랫폼 조건을 통해 시뮬레이터 환경을 간접적으로 테스트하는 것으로 보이는 플랫폼 조건을 평가할 때 targetEnvironment(시뮬레이터) 사용을 검출, 경고 및 제안합니다. (SE-0190)

iOS 9+:

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

스위프트 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

여기서 몇 가지 사항을 명확히 하겠습니다.

  1. TARGET_OS_SIMULATOR는 대부분의 경우 Swift 코드로 설정되어 있지 않습니다.브릿지헤더 때문에 실수로 Import 되는 경우가 있습니다만, 이것은 취약하기 때문에 지원되지 않습니다.그것은 또한 프레임워크에서도 가능하지 않다.이것이 Swift에서 이것이 작동되는지 헷갈리는 이유다.
  2. 시뮬레이터 대신 건축을 사용하지 말 것을 강력히 권합니다.

동적 검사를 수행하려면:

ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil아무 문제 없어요

수 .SIMULATOR_MODEL_IDENTIFIER 는 " "와 문자열을 반환합니다.iPhone10,3.

정적 검사를 수행하려면:

Xcode 9.2 및 이전 버전: 독자적인 Swift 컴파일 플래그를 정의합니다(다른 답변 참조).

Xcode 9.3+는 새로운 targetEnvironment 조건을 사용합니다.

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

Swift 5.2.4 X 코드 11.7


 #if targetEnvironment(simulator)

 #endif

런타임이지만, 여기서는 다른 대부분의 솔루션보다 단순합니다.

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

또는 (특히 프로젝트에서 이미 혼합된 경우) 프리프로세서 매크로를 사용하는 부울을 반환하는 Objective-C 도우미 함수를 호출할 수도 있습니다.

편집: 특히 Xcode 9.3에서는 최적의 솔루션이 아닙니다.Hot Jard의 답변 보기

Swift 1.0이 Arm 이외의 아키텍처를 체크하고 있기 때문에 다음과 같은 이점이 있습니다.

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

     //simulator
#else 
     //device

#endif

이 내선번호가 편리했으면 좋겠어요.

extension UIDevice {
    static var isSimulator: Bool = {
        #if targetEnvironment(simulator)
        return true
        #else
        return false
        #endif
    }()
}

사용방법:

if UIDevice.isSimulator {
    print("running on simulator")
}

최신 시스템:

#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 11, Swift 5

    #if !targetEnvironment(macCatalyst)
    #if targetEnvironment(simulator)
        true
    #else
        false        
    #endif
    #endif

Xcode 7.2(및 이전 버전이지만 얼마나 이전 버전인지 테스트하지 않음)에서는 "Any iOS Simulator"에 대해 플랫폼 고유의 빌드 플래그 "-D TARGET_IPHONE_SIMATOR"을 설정할 수 있습니다.

"Swift Compiler - Customer Flags" 아래에 있는 프로젝트 빌드 설정을 확인하고 "Other Swift Flags"에서 플래그를 설정합니다.빌드 구성 위로 마우스를 가져가면 '더하기' 아이콘을 클릭하여 플랫폼별 플래그를 설정할 수 있습니다.

이 방법에는 몇 가지 장점이 있습니다.1) Swift 코드와 Objective-C 코드에서 동일한 조건부 테스트("#if TARGET_IPHONE_SIMATOR")를 사용할 수 있습니다.2) 각 빌드에만 적용되는 변수를 컴파일할 수 있습니다.

Xcode 빌드 설정 스크린샷

여기 다윈이 모두 묘사되어 있다.Target Conditionals : 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

아래 코드를 사용합니다.

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

기능하는 것Swift 4그리고.Xcode 9.4.1

여기 Xcode 11 Swift의 예가 위의 HotJard의 훌륭한 답변에 근거하고 있습니다.이것 또한,isDeviceBool 및 용도SIMULATOR_UDID이름 대신.변수 할당은 각 행에서 수행되므로 원하는 경우 디버거에서 더 쉽게 검사할 수 있습니다.

import Foundation

// Extensions to UIDevice based on ProcessInfo.processInfo.environment keys
// to determine if the app is running on an actual device or the Simulator.

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

    static var isDevice: Bool {
        let environment = ProcessInfo.processInfo.environment
        let isDevice = environment["SIMULATOR_UDID"] == nil
        return isDevice
    }
}

의 사전 항목도 있습니다.DTPlatformName그 안에는simulator.

다른 답변과 함께요.

Objective-c에서 TargetConditionals를 포함했는지 확인합니다.

#include <TargetConditionals.h>

사용하기 전에TARGET_OS_SIMULATOR.

Swift 3에서 아래 코드를 사용했습니다.

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

Swift 4:

현시점에서는 이 프로세스를 사용하는 것을 선호합니다.디바이스가 시뮬레이터인지 여부와 사용 중인 디바이스의 종류를 알 수 있는 정보 클래스:

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

simModelCode어떤 종류의 시뮬레이터가 시작되었는지 바로 알 수 있는 코드는 아닙니다.필요하다면 현재 아이폰/디바이스 모델을 판별하고 보다 사람이 읽을 수 있는 문자열을 얻기 위해 다른 SO 답변을 볼 수 있습니다.

이것이 누구에게 도움이 될지는 모르겠지만 적어도 현재 버전의 M1 mac은 SIMATOR_MODEL_IDENTIFIER를 NS Process에 전달하지 않는 것 같습니다.정보

나는 사용했다

BOOL isMobile = [[NSProcessInfo processInfo].environment[@"USER"] isEqual:@"mobile"];

신속한 대응이 가능합니다.이것은 깨지기 쉬울지도 모르지만 효과가 있다.

언급URL : https://stackoverflow.com/questions/24869481/how-to-detect-if-app-is-being-built-for-device-or-simulator-in-swift