iOS 앱이 TestFlight 베타 설치를 통해 실행 중인지 런타임에 확인하는 방법


123

TestFlight Beta (iTunes Connect를 통해 제출)와 App Store를 통해 애플리케이션이 설치되었는지 런타임에 감지 할 수 있습니까? 단일 App Bundle을 제출하고 두 가지 모두를 통해 사용할 수 있습니다. 어떤 방식으로 설치되었는지 감지 할 수있는 API가 있습니까? 아니면 영수증에이를 확인할 수있는 정보가 포함되어 있습니까?


4
iTunes Connect를 통한 새로운 TestFlight 베타 테스트에 대해 이야기하고 있습니까? 아니면 TestFlight에 직접 업로드했을 때에 대해 이야기하고 있습니까?
keji 2014 년

새로운 TestFlight 베타는 명확히 할 것입니다
combinatorial

1
-[NSString containsString :]이 ios8에 추가 된 것처럼 보입니다. App Store 자동 테스트가 ios7에서 실행하려고하면 이동하지 마십시오. ([receiptURLString rangeOfString : @ "sandboxReceipt"]. location! = NSNotFound)가 트릭을 수행해야합니다.
rgeorge 2014 년

@rgeorge 감사합니다, 그것은 바보 같은 실수였습니다!
combinatorial

2
appStoreReceiptURL이없는 iOS 6에서 감지하는 것에 대해 물어 보려고했지만 TestFlight 앱은 iOS 8 전용 인 것 같습니다. 그래서-[NSString containsString]은 결국 괜찮을 수 있습니다. 이 때문에 앱 스토어 베타 테스트를 보류했지만 일부 사람들은 레거시 테스트에는 Ad-Hoc, 공개 베타에는 AppStore 베타를 사용하는 하이브리드 테스트 전략을 사용하고있을 수 있으므로 rangeOfString이 여전히 승리합니다.
Gordon Dove

답변:


117

TestFlight Beta를 통해 설치된 응용 프로그램의 경우 영수증 파일의 이름 StoreKit\sandboxReceipt은 일반적인 StoreKit\receipt. 를 사용 [NSBundle appStoreReceiptURL]하면 URL 끝에서 sandboxReceipt를 찾을 수 있습니다.

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSString *receiptURLString = [receiptURL path];
BOOL isRunningTestFlightBeta =  ([receiptURLString rangeOfString:@"sandboxReceipt"].location != NSNotFound);

참고 sandboxReceipt실행중인 로컬 구축하고 위해 시뮬레이터에서 실행 빌드 경우에도 영수증 파일의 이름입니다.


7
언급했듯이 이것은 시뮬레이터가 아닌 장치에서 로컬 테스트를 위해 작동합니다. #if TARGET_IPHONE_SIMULATOR isRunningInTestMode = YES; #endif 다음 분명히, 이것은 필요 # import를 <TargetConditionals.h>
고든 비둘기

13
컴팩트 버전 : Supertop / Haddad[[[[NSBundle mainBundle] appStoreReceiptURL] lastPathComponent] isEqualToString:@"sandboxReceipt"] 를 통한 (TestFlight 분산 바이너리를 실행하는 경우 참)
Nick

2
영수증은 호스트 번들에 대해서만 존재하므로이 방법은 확장 번들에서 사용할 수 없습니다.
jeeeyul

2
내 iOS 8 테스트 StoreKit/sandboxReceipt는 장치 또는 시뮬레이터에서 Xcode를 통해 디버그 빌드로 설치 될 때 발생합니다. 따라서 이것은 testflight 빌드를 다른 모든 빌드 와 정확하게 구별하지 못할 수 있습니다 .
pkamb

3
또한 Ad Hoc 배포로 빌드를 설치할 때 YES를 반환하는 것 같습니다.
켈러

75

combinatorial의 답변을 기반으로 다음 SWIFT 도우미 클래스를 만들었습니다. 이 클래스를 사용하면 디버그, testflight 또는 appstore 빌드인지 확인할 수 있습니다.

enum AppConfiguration {
  case Debug
  case TestFlight
  case AppStore
}

struct Config {
  // This is private because the use of 'appConfiguration' is preferred.
  private static let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
  
  // This can be used to add debug statements.
  static var isDebug: Bool {
    #if DEBUG
      return true
    #else
      return false
    #endif
  }

  static var appConfiguration: AppConfiguration {
    if isDebug {
      return .Debug
    } else if isTestFlight {
      return .TestFlight
    } else {
      return .AppStore
    }
  }
}

프로젝트에서 이러한 메서드를 사용하여 환경별로 다른 추적 ID 또는 연결 문자열을 제공 합니다.

  func getURL(path: String) -> String {    
    switch (Config.appConfiguration) {
    case .Debug:
      return host + "://" + debugBaseUrl + path
    default:
      return host + "://" + baseUrl + path
    }
  }

또는:

  static var trackingKey: String {
    switch (Config.appConfiguration) {
    case .Debug:
      return debugKey
    case .TestFlight:
      return testflightKey
    default:
      return appstoreKey
    }
  }

업데이트 05-02-2016 : #if DEBUG와 같은 전 처리기 매크로를 사용하기위한 전제 조건은 일부 Swift 컴파일러 사용자 정의 플래그를 설정하는 것입니다. 이 답변에 대한 추가 정보 : https://stackoverflow.com/a/24112024/639227


1
@Urkman -D DEBUG플래그를 설정하고 있는지 확인하십시오 . 자세한 내용은 여기 에서 확인할 수 있습니다 .
Caleb

Thnx @Caleb, 전제 조건에 대한 설명을 답변에 추가했습니다.
LorenzoValentijn

1
답변 해 주셔서 감사합니다. 매우 도움이되었습니다. 또한 알아두면 좋은 점 #if targetEnvironment(simulator)은 시뮬레이터에서 실행 중인지 여부를 확인하는 것입니다. 그래서 저는 Simulator / TestFlight / AppStore 옵션을 가지고 있습니다 (내 경우에는 Debug) :-)
JeroenJK

39

시뮬레이터를 설명하는 최신 Swift 버전 (승인 된 답변에 따라) :

private func isSimulatorOrTestFlight() -> Bool {
    guard let path = Bundle.main.appStoreReceiptURL?.path else {
        return false
    }
    return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
}

시뮬레이터를 포함하는 것은 좋지만 모든 경우에 더 이상 적용되지 않으므로 함수 이름을 변경하는 것이 좋습니다.
dbn

2
와! 효과가있다! 대박! 동일한 빌드에 대해 TestFlight에 대해 TRUE를 반환하고 AppStore에 대해 FALSE를 반환합니다 (하나의 프로비저닝으로 하나의 스키마에 빌드 된 하나의 빌드). 완전한! 감사합니다!
Argus

@dbn 더 이상 모든 경우에 이것이 사실이 아닌 이유를 확장 할 수 있습니까?
Ethan

1
@Ethan이 답변은 내 의견을 작성한 후에 편집되었습니다. 메소드 이름은isTestFlight()
dbn


2

Bundle+isProductionSwift 5.2에서 확장 을 사용합니다 .

import Foundation

extension Bundle {
    var isProduction: Bool {
        #if DEBUG
            return false
        #else
            guard let path = self.appStoreReceiptURL?.path else {
                return true
            }
            return !path.contains("sandboxReceipt")
        #endif
    }
}

그때:

if Bundle.main.isProduction {
    // do something
}

-3

프로젝트에 사용하는 한 가지 방법이 있습니다. 단계는 다음과 같습니다.

Xcode에서 프로젝트 설정 (대상이 아닌 프로젝트)으로 이동하고 "베타"구성을 목록에 추가합니다.

여기에 이미지 설명 입력



그런 다음 "베타"구성에서 프로젝트를 실행할 새 구성표를 만들어야합니다. 구성표를 만들려면 여기로 이동하십시오.

여기에 이미지 설명 입력



이 구성표의 이름을 원하는대로 지정하십시오. 이 구성표에 대한 설정을 편집해야합니다. 이렇게하려면 여기를 탭하세요.

여기에 이미지 설명 입력



선택할 수있는 아카이브 탭을 선택하십시오. Build configuration

여기에 이미지 설명 입력



그런 다음 다음 Config$(CONFIGURATION)같이 프로젝트 정보 속성 목록에 값 이 있는 키를 추가해야합니다 .

여기에 이미지 설명 입력



그런 다음 베타 빌드에 특정한 작업을 수행하기 위해 코드에서 필요한 것이 무엇입니까?

let config = Bundle.main.object(forInfoDictionaryKey: "Config") as! String
if config == "Debug" {
  // app running in debug configuration
}
else if config == "Release" {
  // app running in release configuration
}
else if config == "Beta" {
  // app running in beta configuration
}

6
이것은 유용한 기술이지만 질문에 답하지 않습니다. 단일 바이너리가 App Store에 제출되고 TestFlight를 통한 다운로드에서 실행하거나 App Store에서 다운로드 한 후 승인 된 실행 후에 실행할 수 있습니다. 문제는 실행중인 버전을 감지하는 것입니다.
조합

처음에 2 개의 아카이브를 만드는 옵션이 있습니까? 하나는 testflight 용이고 다른 하나는 앱 스토어 용입니다.
클레멘

가능하지만 빌드 번호가 달라야합니다. 그리고 그것은 하나가 아닌 두 개의 빌드를 관리하는 것을 의미합니다.
조합

좋아요, 제 생각에는 그만한 가치가 있습니다. 특히 지속적인 통합 도구를 사용하는 경우.
Klemen

@KlemenZagar, 귀하의 접근 방식은 잘 알려져 있고 좋은 접근 방식이지만 질문에 대한 답변은 없습니다.
Stanislav Pankevich
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.