App Store Connect adds your app to the review queue and changes its status to Waiting for Review. To get approval, your build must comply with the App Store Review Guidelines. Approval usually takes no more than 48 hours.
Open your email invitation or tap the public link on your iOS or iPadOS device. Tap View in TestFlight or Start Testing; or tap Install or Update for the app you want to test. If you're testing an iOS app that includes an iMessage app, launch the beta app from the Home Screen.
Download TestFlight app and start testing Invited testers will receive an email with a link to test your app. To be able to test, they will first have to download the TestFlight app. After accepting the invitation, they will be directed to the TestFlight app and they will be prompted to install to app to be tested.
Every new release in TestFlight expires after 90 days (3 months). This will never be a problem as we're committed to pushing regular updates - generally every month.
For an application installed through TestFlight Beta the receipt file is named StoreKit\sandboxReceipt
vs the usual StoreKit\receipt
. Using [NSBundle appStoreReceiptURL]
you can look for sandboxReceipt at the end of the URL.
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSString *receiptURLString = [receiptURL path];
BOOL isRunningTestFlightBeta = ([receiptURLString rangeOfString:@"sandboxReceipt"].location != NSNotFound);
Note that sandboxReceipt
is also the name of the receipt file when running builds locally and for builds run in the simulator.
Based on combinatorial's answer I created the following SWIFT helper class. With this class you can determine if it's a debug, testflight or appstore build.
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
}
}
}
We use these methods in our project to supply different tracking id's or connection string per environment:
func getURL(path: String) -> String {
switch (Config.appConfiguration) {
case .Debug:
return host + "://" + debugBaseUrl + path
default:
return host + "://" + baseUrl + path
}
}
OR:
static var trackingKey: String {
switch (Config.appConfiguration) {
case .Debug:
return debugKey
case .TestFlight:
return testflightKey
default:
return appstoreKey
}
}
UPDATE 05-02-2016: A prerequisite to use a preprocessor macro like #if DEBUG is to set some Swift Compiler Custom Flags. More information in this answer: https://stackoverflow.com/a/24112024/639227
Modern Swift version, which accounts for Simulators (based on accepted answer):
private func isSimulatorOrTestFlight() -> Bool {
guard let path = Bundle.main.appStoreReceiptURL?.path else {
return false
}
return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
}
I use extension Bundle+isProduction
on 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
}
}
Then:
if Bundle.main.isProduction {
// do something
}
This does not work any more. Use other method.
This also works:
if NSBundle.mainBundle().pathForResource("embedded", ofType: "mobileprovision") != nil {
// TestFlight
} else {
// App Store (and Apple reviewers too)
}
Found in Detect if iOS App is Downloaded from Apple's Testflight
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With