Jak stwierdzić w czasie wykonywania, czy aplikacja na iOS działa podczas instalacji TestFlight Beta

123

Czy w czasie wykonywania można wykryć, że aplikacja została zainstalowana za pośrednictwem TestFlight Beta (przesłana za pośrednictwem iTunes Connect) w porównaniu z App Store? Możesz przesłać jeden pakiet aplikacji i udostępnić go w obu. Czy istnieje interfejs API, który może wykryć, w jaki sposób został zainstalowany? A może pokwitowanie zawiera informacje, które pozwalają to ustalić?

kombinatoryczny
źródło
4
Żeby było jasne, mówisz o nowych testach beta TestFlight za pośrednictwem iTunes Connect? A może mówisz o tym, kiedy przesłałeś bezpośrednio do TestFlight?
keji
Nowa beta TestFlight wyjaśni
kombinatoryczne
1
Wygląda na to, że - [NSString zawieraString:] jest dodatkiem ios8. Jeśli autotest App Store spróbuje uruchomić go na ios7, nie idź. ([receiverURLString rangeOfString: @ "sandboxReceipt"]. location! = NSNotFound) powinno załatwić sprawę.
rgeorge
@rgeorge thanks, to był głupi błąd!
kombinatoryczne
2
Chciałem zapytać o wykrywanie na iOS 6, który nie ma appStoreReceiptURL, ale wygląda na to, że aplikacja TestFlight jest tylko iOS 8; więc - mimo wszystko [NSString zawieraString] może być w porządku. Z tego powodu wstrzymałem testy beta App Store, ale wydaje mi się, że niektórzy ludzie mogą używać strategii testowania hybrydowego, z Ad-Hoc do testowania starszych wersji i AppStore beta do publicznej wersji beta, więc rangeOfString nadal wygrywa.
Gordon Dove

Odpowiedzi:

118

W przypadku aplikacji zainstalowanej za pośrednictwem TestFlight Beta plik z potwierdzeniem ma nazwę zamiast StoreKit\sandboxReceiptzwykłej StoreKit\receipt. Używając [NSBundle appStoreReceiptURL]możesz poszukać sandboxReceipt na końcu adresu URL.

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

Zauważ, że sandboxReceiptjest to również nazwa pliku potwierdzenia, gdy kompilacje są uruchamiane lokalnie i kompilacje uruchamiane w symulatorze.

kombinatoryczny
źródło
7
Jak wspomniano, działa to w przypadku testów lokalnych na urządzeniu, ale nie w symulatorze. Dodałem coś takiego jak #if TARGET_IPHONE_SIMULATOR isRunningInTestMode = YES; #endif Oczywiście wymaga to #import <TargetConditionals.h>
Gordon Dove
13
Wersja kompaktowa: [[[[NSBundle mainBundle] appStoreReceiptURL] lastPathComponent] isEqualToString:@"sandboxReceipt"](prawda, jeśli uruchomiono rozproszony plik binarny TestFlight) przez Supertop / Haddad
Nick
2
Tej metody nie można używać w pakietach rozszerzeń, ponieważ potwierdzenie istnieje tylko dla pakietu hosta.
jeeeyul
2
Moje testy iOS 8 kończą się StoreKit/sandboxReceiptinstalacją jako kompilacja debugowania za pośrednictwem Xcode na urządzeniu lub w symulatorze. Może to więc nie odróżniać dokładnie wersji testowych od wszystkich innych kompilacji.
pkamb
3
Wydaje się również, że zwraca TAK podczas instalowania kompilacji z dystrybucją Ad Hoc.
Keller
75

Na podstawie odpowiedzi kombinatorycznej utworzyłem następującą klasę pomocniczą SWIFT. Za pomocą tej klasy możesz określić, czy jest to kompilacja debugowania, lotu testowego czy sklepu z aplikacjami.

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
    }
  }
}

W naszym projekcie używamy tych metod, aby dostarczyć różne identyfikatory śledzenia lub parametry połączenia dla każdego środowiska:

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

LUB:

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

AKTUALIZACJA 05-02-2016: Warunkiem wstępnym użycia makra preprocesora, takiego jak #if DEBUG, jest ustawienie niektórych niestandardowych flag Swift Compiler. Więcej informacji w tej odpowiedzi: https://stackoverflow.com/a/24112024/639227

LorenzoValentijn
źródło
1
@Urkman Upewnij się, że ustawiasz -D DEBUGflagę. Więcej informacji można znaleźć tutaj .
Caleb,
Dzięki @Caleb, dodałem więcej wyjaśnień na temat warunków wstępnych do odpowiedzi.
LorenzoValentijn
1
Dziękuję za odpowiedź, okazała się bardzo pomocna! Warto również wiedzieć, na podstawie tego #if targetEnvironment(simulator)możesz określić, czy korzystasz z symulatora. Więc mam opcje Simulator / TestFlight / AppStore (co jest w moim przypadku preferowane Debug) :-)
JeroenJK
39

Nowoczesna wersja Swift, która uwzględnia Symulatory (na podstawie zaakceptowanej odpowiedzi):

private func isSimulatorOrTestFlight() -> Bool {
    guard let path = Bundle.main.appStoreReceiptURL?.path else {
        return false
    }
    return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
}
Serhii Yakovenko
źródło
Fajnie jest dołączyć symulator, ale możesz chcieć zmienić nazwę funkcji, ponieważ nie jest to już prawdą we wszystkich przypadkach.
dbn
2
ŁAŁ! To działa! Niesamowite! Zwraca TRUE dla TestFlight i FALSE dla AppStore dla tej samej kompilacji (jedna kompilacja zbudowana w jednym schemacie z jedną obsługą administracyjną). Idealny! Dziękuję Ci!
Argus
@dbn czy możesz wyjaśnić, dlaczego nie jest to już prawdą we wszystkich przypadkach?
Ethan
1
@Ethan ta odpowiedź została zmieniona po tym, jak napisałem komentarz; dawniej była to nazwa metodyisTestFlight()
dbn
6

Aktualizacja

To już nie działa. Użyj innej metody.

Oryginalna odpowiedź

Działa to również:

if NSBundle.mainBundle().pathForResource("embedded", ofType: "mobileprovision") != nil {
    // TestFlight
} else {
    // App Store (and Apple reviewers too)
}

Znalezione w Wykryj, czy aplikacja iOS jest pobrana z Apple's Testflight

Marián Černý
źródło
2

Używam rozszerzenia Bundle+isProductionw Swift 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
    }
}

Następnie:

if Bundle.main.isProduction {
    // do something
}
Denis Kutlubaev
źródło
-3

Jest jeden sposób, w jaki używam go w moich projektach. Oto kroki.

W Xcode przejdź do ustawień projektu (projekt, a nie cel) i dodaj konfigurację „beta” do listy:

wprowadź opis obrazu tutaj



Następnie należy stworzyć nowy schemat, który będzie uruchamiał projekt w konfiguracji „beta”. Aby utworzyć schemat, przejdź tutaj:

wprowadź opis obrazu tutaj



Nazwij ten schemat, jak chcesz. Należy edytować ustawienia tego schematu. Aby to zrobić, dotknij tutaj:

wprowadź opis obrazu tutaj



Wybierz kartę Archiwum, w której możesz wybrać Build configuration

wprowadź opis obrazu tutaj



Następnie musisz dodać klucz Configz wartością $(CONFIGURATION)listy właściwości informacji o projektach w następujący sposób:

wprowadź opis obrazu tutaj



W takim razie chodzi tylko o to, czego potrzebujesz w kodzie, aby zrobić coś specyficznego dla kompilacji beta:

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
}
Klemen
źródło
6
Chociaż jest to pomocna technika, nie odpowiada na pytanie. Pojedynczy plik binarny jest przesyłany do App Store i można go uruchomić od momentu pobrania za pośrednictwem TestFlight lub później po zatwierdzonym uruchomieniu po pobraniu z App Store. Pytanie dotyczy wykrycia, która wersja jest uruchomiona.
kombinatoryczne
Czy w pierwszej kolejności jest możliwość zrobienia 2 archiwów. jeden do lotów testowych jeden do sklepu z aplikacjami.
Klemen
Jest to możliwe, ale muszą mieć różne numery kompilacji. A to oznacza zarządzanie dwoma kompilacjami zamiast jednej.
kombinatoryczne
ok, moim zdaniem warto. Zwłaszcza jeśli korzystasz z narzędzi ciągłej integracji.
Klemen
@KlemenZagar, Twoje podejście jest dobrze znane i dobre, ale nie odpowiada na pytanie.
Stanislav Pankevich