Look up TestFlight flag asynchronously (#352)

Xcode has been quite obnoxious recently with this issue. Start the app
with the most restrictive type (.undefined), relax restrictions after
looking up sandbox and app receipt.
This commit is contained in:
Davide De Rosa 2023-09-10 00:52:39 +02:00 committed by GitHub
parent 33d9e05907
commit a38e3fed7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 34 deletions

View File

@ -50,10 +50,10 @@
0E34AC7827F840890042F2AB /* OrganizerView+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */; }; 0E34AC7827F840890042F2AB /* OrganizerView+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */; };
0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */; }; 0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */; };
0E35C09A280E95BB0071FA35 /* ProviderProfileAvailability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */; }; 0E35C09A280E95BB0071FA35 /* ProviderProfileAvailability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */; };
0E3A3C102AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C0F2AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift */; };
0E3A3C132AAB7C480003A5F6 /* UpgradeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C112AAB7C470003A5F6 /* UpgradeManager.swift */; }; 0E3A3C132AAB7C480003A5F6 /* UpgradeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C112AAB7C470003A5F6 /* UpgradeManager.swift */; };
0E3A3C142AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C122AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift */; }; 0E3A3C142AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C122AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift */; };
0E3A3C162AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C152AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift */; }; 0E3A3C162AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C152AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift */; };
0E3A3C102AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A3C0F2AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift */; };
0E3A593C2A50975700B3FE40 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A593B2A50975700B3FE40 /* ErrorHandler.swift */; }; 0E3A593C2A50975700B3FE40 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3A593B2A50975700B3FE40 /* ErrorHandler.swift */; };
0E3B7FCD27E47B3700C66F13 /* AddHostView+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FCC27E47B3700C66F13 /* AddHostView+Name.swift */; }; 0E3B7FCD27E47B3700C66F13 /* AddHostView+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FCC27E47B3700C66F13 /* AddHostView+Name.swift */; };
0E3B7FD627E5173A00C66F13 /* ProfileView+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */; }; 0E3B7FD627E5173A00C66F13 /* ProfileView+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */; };
@ -176,7 +176,7 @@
0ED2B36027D3C99100FD8EA9 /* PassepartoutWireGuardTunnel.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0ED2B34A27D3C77800FD8EA9 /* PassepartoutWireGuardTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 0ED2B36027D3C99100FD8EA9 /* PassepartoutWireGuardTunnel.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0ED2B34A27D3C77800FD8EA9 /* PassepartoutWireGuardTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
0ED2B36727D3C9A300FD8EA9 /* WireGuardAppExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 0ED2B36627D3C9A300FD8EA9 /* WireGuardAppExtension */; }; 0ED2B36727D3C9A300FD8EA9 /* WireGuardAppExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 0ED2B36627D3C9A300FD8EA9 /* WireGuardAppExtension */; };
0ED30DCC27EA197D0057D8A3 /* RevealingSecureField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DCB27EA197C0057D8A3 /* RevealingSecureField.swift */; }; 0ED30DCC27EA197D0057D8A3 /* RevealingSecureField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DCB27EA197C0057D8A3 /* RevealingSecureField.swift */; };
0ED30DCF27EA1EF80057D8A3 /* PaywallView+Beta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DCE27EA1EF80057D8A3 /* PaywallView+Beta.swift */; }; 0ED30DCF27EA1EF80057D8A3 /* PaywallView+Restricted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DCE27EA1EF80057D8A3 /* PaywallView+Restricted.swift */; };
0ED30DD227EA1F650057D8A3 /* PaywallView+Purchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */; }; 0ED30DD227EA1F650057D8A3 /* PaywallView+Purchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */; };
0ED30DDB27EA351C0057D8A3 /* Constants+Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DDA27EA351C0057D8A3 /* Constants+Tunnel.swift */; }; 0ED30DDB27EA351C0057D8A3 /* Constants+Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED30DDA27EA351C0057D8A3 /* Constants+Tunnel.swift */; };
0ED30DDD27EA35230057D8A3 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; }; 0ED30DDD27EA35230057D8A3 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB17EA127D2263700D473B5 /* Constants.swift */; };
@ -344,10 +344,10 @@
0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Scene.swift"; sourceTree = "<group>"; }; 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Scene.swift"; sourceTree = "<group>"; };
0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnDemandView+SSID.swift"; sourceTree = "<group>"; }; 0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnDemandView+SSID.swift"; sourceTree = "<group>"; };
0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProfileAvailability.swift; sourceTree = "<group>"; }; 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProfileAvailability.swift; sourceTree = "<group>"; };
0E3A3C0F2AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyValueStore+CloudKit.swift"; sourceTree = "<group>"; };
0E3A3C112AAB7C470003A5F6 /* UpgradeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeManager.swift; sourceTree = "<group>"; }; 0E3A3C112AAB7C470003A5F6 /* UpgradeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeManager.swift; sourceTree = "<group>"; };
0E3A3C122AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultUpgradeManagerStrategy.swift; sourceTree = "<group>"; }; 0E3A3C122AAB7C480003A5F6 /* DefaultUpgradeManagerStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultUpgradeManagerStrategy.swift; sourceTree = "<group>"; };
0E3A3C152AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeManagerStrategy.swift; sourceTree = "<group>"; }; 0E3A3C152AAB8AB80003A5F6 /* UpgradeManagerStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeManagerStrategy.swift; sourceTree = "<group>"; };
0E3A3C0F2AA9AA530003A5F6 /* KeyValueStore+CloudKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyValueStore+CloudKit.swift"; sourceTree = "<group>"; };
0E3A593B2A50975700B3FE40 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = "<group>"; }; 0E3A593B2A50975700B3FE40 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = "<group>"; };
0E3B7FCC27E47B3700C66F13 /* AddHostView+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddHostView+Name.swift"; sourceTree = "<group>"; }; 0E3B7FCC27E47B3700C66F13 /* AddHostView+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddHostView+Name.swift"; sourceTree = "<group>"; };
0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+VPN.swift"; sourceTree = "<group>"; }; 0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+VPN.swift"; sourceTree = "<group>"; };
@ -497,7 +497,7 @@
0ED2B34A27D3C77800FD8EA9 /* PassepartoutWireGuardTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassepartoutWireGuardTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 0ED2B34A27D3C77800FD8EA9 /* PassepartoutWireGuardTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassepartoutWireGuardTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
0ED2B35A27D3C94F00FD8EA9 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; }; 0ED2B35A27D3C94F00FD8EA9 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
0ED30DCB27EA197C0057D8A3 /* RevealingSecureField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevealingSecureField.swift; sourceTree = "<group>"; }; 0ED30DCB27EA197C0057D8A3 /* RevealingSecureField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevealingSecureField.swift; sourceTree = "<group>"; };
0ED30DCE27EA1EF80057D8A3 /* PaywallView+Beta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaywallView+Beta.swift"; sourceTree = "<group>"; }; 0ED30DCE27EA1EF80057D8A3 /* PaywallView+Restricted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaywallView+Restricted.swift"; sourceTree = "<group>"; };
0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaywallView+Purchase.swift"; sourceTree = "<group>"; }; 0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaywallView+Purchase.swift"; sourceTree = "<group>"; };
0ED30DDA27EA351C0057D8A3 /* Constants+Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constants+Tunnel.swift"; sourceTree = "<group>"; }; 0ED30DDA27EA351C0057D8A3 /* Constants+Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constants+Tunnel.swift"; sourceTree = "<group>"; };
0ED31C3920CF39510027975F /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; 0ED31C3920CF39510027975F /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
@ -676,8 +676,8 @@
0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */, 0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */,
0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */, 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */,
0EF0FAF527DD0211007EB181 /* PaywallView.swift */, 0EF0FAF527DD0211007EB181 /* PaywallView.swift */,
0ED30DCE27EA1EF80057D8A3 /* PaywallView+Beta.swift */,
0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */, 0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */,
0ED30DCE27EA1EF80057D8A3 /* PaywallView+Restricted.swift */,
0E44689527B051C300A14CE4 /* ProfileView.swift */, 0E44689527B051C300A14CE4 /* ProfileView.swift */,
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */, 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */,
0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */, 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */,
@ -1481,7 +1481,7 @@
0E3A3C132AAB7C480003A5F6 /* UpgradeManager.swift in Sources */, 0E3A3C132AAB7C480003A5F6 /* UpgradeManager.swift in Sources */,
0E96D3052872010A005EFBCF /* DefaultLightVPNManager.swift in Sources */, 0E96D3052872010A005EFBCF /* DefaultLightVPNManager.swift in Sources */,
0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */, 0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */,
0ED30DCF27EA1EF80057D8A3 /* PaywallView+Beta.swift in Sources */, 0ED30DCF27EA1EF80057D8A3 /* PaywallView+Restricted.swift in Sources */,
0ECF71EE27B6A99300CDB528 /* AccountView.swift in Sources */, 0ECF71EE27B6A99300CDB528 /* AccountView.swift in Sources */,
0E71ACF727C107CA00F85C4B /* DebugLogView.swift in Sources */, 0E71ACF727C107CA00F85C4B /* DebugLogView.swift in Sources */,
0EF0FAF927DD212C007EB181 /* IntentActivity.swift in Sources */, 0EF0FAF927DD212C007EB181 /* IntentActivity.swift in Sources */,

View File

@ -39,10 +39,6 @@ extension Constants {
static let appStoreId: String = bundleConfig("appstore_id") static let appStoreId: String = bundleConfig("appstore_id")
static let appGroupId: String = bundleConfig("group_id") static let appGroupId: String = bundleConfig("group_id")
static let isBeta: Bool = {
Bundle.main.isTestFlight
}()
} }
enum CloudKit { enum CloudKit {
@ -56,7 +52,7 @@ extension Constants {
} }
enum InApp { enum InApp {
static var appType: ProductManager.AppType { static var overriddenAppType: ProductManager.AppType? {
if let envString = ProcessInfo.processInfo.environment["APP_TYPE"], if let envString = ProcessInfo.processInfo.environment["APP_TYPE"],
let envValue = Int(envString), let envValue = Int(envString),
let testAppType = ProductManager.AppType(rawValue: envValue) { let testAppType = ProductManager.AppType(rawValue: envValue) {
@ -68,7 +64,7 @@ extension Constants {
return testAppType return testAppType
} }
return App.isBeta ? .beta : .freemium return nil
} }
#if targetEnvironment(macCatalyst) #if targetEnvironment(macCatalyst)

View File

@ -43,7 +43,7 @@ final class AppContext {
self.coreContext = coreContext self.coreContext = coreContext
productManager = ProductManager( productManager = ProductManager(
appType: Constants.InApp.appType, overriddenAppType: Constants.InApp.overriddenAppType,
buildProducts: Constants.InApp.buildProducts buildProducts: Constants.InApp.buildProducts
) )

View File

@ -29,21 +29,40 @@ import Kvitto
import PassepartoutLibrary import PassepartoutLibrary
import StoreKit import StoreKit
@MainActor
final class ProductManager: NSObject, ObservableObject { final class ProductManager: NSObject, ObservableObject {
enum AppType: Int { enum AppType: Int {
case undefined = -1
case freemium = 0 case freemium = 0
case beta = 1 case beta = 1
case fullVersion = 2 case fullVersion = 2
var isRestricted: Bool {
switch self {
case .undefined, .beta:
return true
default:
return false
}
}
} }
let appType: AppType private let overriddenAppType: AppType?
private let sandboxChecker: SandboxChecker
private var subscriptions: Set<AnyCancellable>
let buildProducts: BuildProducts let buildProducts: BuildProducts
let didRefundProducts = PassthroughSubject<Void, Never>() let didRefundProducts = PassthroughSubject<Void, Never>()
@Published private(set) var appType: AppType
@Published private(set) var isRefreshingProducts = false @Published private(set) var isRefreshingProducts = false
@Published private(set) var products: [SKProduct] @Published private(set) var products: [SKProduct]
@ -73,10 +92,14 @@ final class ProductManager: NSObject, ObservableObject {
private var refreshRequest: SKReceiptRefreshRequest? private var refreshRequest: SKReceiptRefreshRequest?
init(appType: AppType, buildProducts: BuildProducts) { init(overriddenAppType: AppType?, buildProducts: BuildProducts) {
self.appType = appType self.overriddenAppType = overriddenAppType
self.buildProducts = buildProducts self.buildProducts = buildProducts
appType = .undefined
sandboxChecker = SandboxChecker(bundle: .main)
subscriptions = []
products = [] products = []
inApp = InApp() inApp = InApp()
purchasedAppBuild = nil purchasedAppBuild = nil
@ -88,8 +111,20 @@ final class ProductManager: NSObject, ObservableObject {
reloadReceipt() reloadReceipt()
SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(self)
refreshProducts() refreshProducts()
sandboxChecker.$isSandbox
.dropFirst() // ignore initial value
.sink { [weak self] in
guard let self else {
return
}
self.appType = overriddenAppType ?? ($0 ? .beta : .freemium)
pp_log.info("App type: \(self.appType)")
self.reloadReceipt()
}.store(in: &subscriptions)
sandboxChecker.check()
} }
deinit { deinit {
@ -294,7 +329,7 @@ private extension ProductManager {
let receipt = Receipt(contentsOfURL: url) let receipt = Receipt(contentsOfURL: url)
// in TestFlight, attempt fallback to existing release receipt // in TestFlight, attempt fallback to existing release receipt
if Bundle.main.isTestFlight { if appType == .beta {
guard let receipt else { guard let receipt else {
let releaseUrl = url.deletingLastPathComponent().appendingPathComponent("receipt") let releaseUrl = url.deletingLastPathComponent().appendingPathComponent("receipt")
guard releaseUrl != url else { guard releaseUrl != url else {

View File

@ -47,6 +47,8 @@ struct PassepartoutApp: App {
} }
private extension View { private extension View {
@MainActor
func onIntentActivity(_ activity: IntentActivity<VPNManager>) -> some View { func onIntentActivity(_ activity: IntentActivity<VPNManager>) -> some View {
onContinueUserActivity(activity.name) { userActivity in onContinueUserActivity(activity.name) { userActivity in

View File

@ -1,5 +1,5 @@
// //
// PaywallView+Beta.swift // PaywallView+Restricted.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 3/22/22. // Created by Davide De Rosa on 3/22/22.
@ -26,11 +26,12 @@
import SwiftUI import SwiftUI
extension PaywallView { extension PaywallView {
struct BetaView: View { struct RestrictedView: View {
var body: some View { var body: some View {
Text("The requested feature in unavailable in beta.") Text("The requested feature in unavailable in this build.")
.navigationTitle("Beta") .multilineTextAlignment(.center)
.padding() .padding()
.navigationTitle("Restricted")
} }
} }
} }

View File

@ -51,8 +51,8 @@ struct PaywallView: View {
var body: some View { var body: some View {
Group { Group {
if productManager.appType == .beta { if productManager.appType.isRestricted {
BetaView() RestrictedView()
} else { } else {
PurchaseView( PurchaseView(
isPresented: $isPresented, isPresented: $isPresented,

View File

@ -1,5 +1,5 @@
// //
// Utils+TestFlight.swift // SandboxChecker.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 5/18/22. // Created by Davide De Rosa on 5/18/22.
@ -28,19 +28,35 @@ import Foundation
// https://stackoverflow.com/a/32238344/784615 // https://stackoverflow.com/a/32238344/784615
// https://gist.github.com/lukaskubanek/cbfcab29c0c93e0e9e0a16ab09586996 // https://gist.github.com/lukaskubanek/cbfcab29c0c93e0e9e0a16ab09586996
extension Bundle { @MainActor
public var isTestFlight: Bool { public final class SandboxChecker: ObservableObject {
#if targetEnvironment(simulator) private let bundle: Bundle
true
@Published public private(set) var isSandbox = false
public init(bundle: Bundle) {
self.bundle = bundle
}
public func check() {
Task {
isSandbox = await isSandboxBuild()
pp_log.info("Sandbox build: \(isSandbox)")
}
}
private func isSandboxBuild() async -> Bool {
#if os(iOS)
bundle.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
#elseif targetEnvironment(macCatalyst) || os(macOS) #elseif targetEnvironment(macCatalyst) || os(macOS)
var status = noErr var status = noErr
var code: SecStaticCode? var code: SecStaticCode?
status = SecStaticCodeCreateWithPath(bundleURL as CFURL, [], &code) status = SecStaticCodeCreateWithPath(bundle.bundleURL as CFURL, [], &code)
guard status == noErr else { guard status == noErr else {
return false return false
} }
guard let code = code else { guard let code else {
return false return false
} }
@ -53,7 +69,7 @@ extension Bundle {
guard status == noErr else { guard status == noErr else {
return false return false
} }
guard let requirement = requirement else { guard let requirement else {
return false return false
} }
@ -63,8 +79,6 @@ extension Bundle {
requirement requirement
) )
return status == errSecSuccess return status == errSecSuccess
#elseif os(iOS)
appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
#else #else
false false
#endif #endif