如何在运行时判断 iOS 应用程序是不是正在通过 TestFlight Beta 安装运行
Posted
技术标签:
【中文标题】如何在运行时判断 iOS 应用程序是不是正在通过 TestFlight Beta 安装运行【英文标题】:How to tell at runtime whether an iOS app is running through a TestFlight Beta install如何在运行时判断 iOS 应用程序是否正在通过 TestFlight Beta 安装运行 【发布时间】:2014-11-22 18:17:57 【问题描述】:是否可以在运行时检测到应用程序已通过 TestFlight Beta(通过 iTunes Connect 提交)而不是 App Store 安装?您可以提交单个应用程序包并通过两者提供。是否有可以检测其安装方式的 API?或者收据是否包含可以确定这一点的信息?
【问题讨论】:
为了清楚起见,您是在谈论通过 iTunes Connect 进行的新 TestFlight beta 测试?还是说你是直接上传到TestFlight的时候? 新的TestFlight beta,将澄清 看起来 -[NSString containsString:] 是 ios8 添加的。如果 App Store 自动测试尝试在 ios7 上运行它,那就不行了。 ([receiptURLString rangeOfString:@"sandboxReceipt"].location != NSNotFound) 应该可以解决问题。 @rgeorge 谢谢,这是一个愚蠢的错误! 我想问一下在没有 appStoreReceiptURL 的 iOS 6 上检测,但似乎 TestFlight 应用程序仅适用于 iOS 8;所以 -[NSString containsString] 毕竟可能没问题。因此,我已暂停应用商店 beta 测试,但我猜有些人可能会使用混合测试策略,即 Ad-Hoc 用于旧版测试,而 AppStore beta 用于公共测试版,因此 rangeOfString 仍然胜出。 【参考方案1】:对于通过 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
也是在本地运行构建和在模拟器中运行构建时收据文件的名称。
Swift 版本:
let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
【讨论】:
如前所述,这适用于设备上的本地测试,但不适用于模拟器。我添加了类似#if TARGET_IPHONE_SIMULATOR isRunningInTestMode = YES; #endif 显然,这需要#import[[[[NSBundle mainBundle] appStoreReceiptURL] lastPathComponent] isEqualToString:@"sandboxReceipt"]
(如果运行 TestFlight 分布式二进制文件则为真)通过Supertop/Haddad
此方法不能用于扩展包,因为收据只存在于主机包中。
在使用 Ad Hoc 分发安装构建时似乎也返回 YES。
在 6 年后的 2020 年按预期工作。【参考方案2】:
基于combinatorial's answer,我创建了以下 SWIFT 帮助程序类。使用此类,您可以确定它是调试、测试飞行还是应用商店构建。
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
2016 年 5 月 2 日更新: 使用 #if DEBUG 之类的预处理器宏的先决条件是设置一些 Swift 编译器自定义标志。此答案中的更多信息:https://***.com/a/24112024/639227
【讨论】:
@Urkman 确保您设置了-D DEBUG
标志。更多信息可以在here找到。
Thnx @Caleb,我对答案的先决条件添加了更多解释。
感谢您的回答,我发现它很有帮助!也很高兴知道,使用#if targetEnvironment(simulator)
可以确定您是否在模拟器中运行。所以我有 Simulator/TestFlight/AppStore 选项(在我的情况下,这比 Debug
更受欢迎):-)【参考方案3】:
现代 Swift 版本,用于模拟器(基于接受的答案):
private func isSimulatorOrTestFlight() -> Bool
guard let path = Bundle.main.appStoreReceiptURL?.path else
return false
return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
【讨论】:
很高兴包含模拟器,但您可能需要更改函数名称,因为它不再适用于所有情况。 哇!有用!惊人的!对于同一构建(在一个方案中构建的一个构建,具有一个配置),对于 TestFlight 返回 TRUE,对于 AppStore 返回 FALSE。完美的!谢谢! @dbn 你能详细说明为什么这不再适用于所有情况吗? @Ethan 这个答案是在我发表评论后编辑的;方法名称以前是isTestFlight()
【参考方案4】:
我在 Swift 5.2 上使用扩展名 Bundle+isProduction
:
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
【讨论】:
【参考方案5】:更新
这不再起作用了。使用其他方法。
原答案
这也有效:
if NSBundle.mainBundle().pathForResource("embedded", ofType: "mobileprovision") != nil
// TestFlight
else
// App Store (and Apple reviewers too)
发现于Detect if iOS App is Downloaded from Apple's Testflight
【讨论】:
可以用这个方法查看应用是在review还是live吗?【参考方案6】:我有一种方法可以将它用于我的项目。步骤如下。
在 Xcode 中,转到项目设置(项目,而不是目标)并将“beta”配置添加到列表中:
然后你需要创建一个新的方案,它将在“beta”配置中运行项目。要创建方案,请转到此处:
将此方案命名为您想要的任何名称。您应该编辑此方案的设置。为此,请点按此处:
选择存档选项卡,您可以在其中选择Build configuration
然后您需要在项目信息属性列表中添加一个值为$(CONFIGURATION)
的键Config
,如下所示:
然后,您需要在代码中执行特定于 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
【讨论】:
虽然这是一种有用的技术,但它并不能回答问题。单个二进制文件被提交到 App Store,可以通过 TestFlight 下载运行,也可以在从 App Store 下载后批准运行后运行。问题是关于检测哪个版本正在运行。 是否可以选择首先制作 2 个存档。一个用于测试,一个用于应用商店。 这是可能的,但它们必须具有不同的内部版本号。这意味着管理两个构建而不是一个。 好的,在我看来这是值得的。特别是如果您使用持续集成工具。 @KlemenZagar,您的方法是众所周知的好方法,但它没有回答问题。以上是关于如何在运行时判断 iOS 应用程序是不是正在通过 TestFlight Beta 安装运行的主要内容,如果未能解决你的问题,请参考以下文章
如何判断 CLLocationManager 是不是正在主动扫描信标?