Tengo un código para suscripciones con renovación automática, cómo cerrar la ventana de suscripción después de pagar la suscripción y mostrar la estructura ContentView().
import Foundation import StoreKit typealias FetchCompletionHandler = (([SKProduct]) -> Void) typealias PurchaseCompletionHandler = ((SKPaymentTransaction?) -> Void) class Store: NSObject, ObservableObject { @Published var allRecipes = [Recipe]() private let allProductIdentifiers = Set([ "PRODUCT_ID_APP_STORE_CONNECT"]) private var completedPurchases = [String]() { didSet { DispatchQueue.main.async { [weak self] in guard let self = self else { return } for index in self.allRecipes.indices { self.allRecipes[index].isLocked = !self.completedPurchases.contains(self.allRecipes[index].id) } } } } private var productsRequest: SKProductsRequest? private var fetchedProducts = [SKProduct]() private var fetchCompletionHandler: FetchCompletionHandler? private var purchaseCompletionHandler: PurchaseCompletionHandler? private let userDefaultsKey = "PRODUCT_ID_APP_STORE_CONNECT" override init() { super.init() startObservingPaymentQueue() fetchProducts { products in self.allRecipes = products.map { Recipe(product: $0) } } } func loadStorePurchases() { if let storePurchases = UserDefaults.standard.object(forKey: userDefaultsKey) as? [String] { self.completedPurchases = storePurchases } } private func startObservingPaymentQueue() { SKPaymentQueue.default().add(self) } private func fetchProducts(_ completion: @escaping FetchCompletionHandler) { guard self.productsRequest == nil else { return } fetchCompletionHandler = completion productsRequest = SKProductsRequest(productIdentifiers: allProductIdentifiers) productsRequest?.delegate = self productsRequest?.start() } private func buy(_ product: SKProduct, completion: @escaping PurchaseCompletionHandler) { purchaseCompletionHandler = completion let payment = SKPayment(product: product) SKPaymentQueue.default().add(payment) } } extension Store { func product(for identifier: String) -> SKProduct? { return fetchedProducts.first(where: { $0.productIdentifier == identifier }) } func purchaseProduct(_ product: SKProduct) { startObservingPaymentQueue() buy(product) { _ in } } func restorePurchases() { SKPaymentQueue.default().restoreCompletedTransactions() } } extension Store: SKPaymentTransactionObserver { func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { var shouldFinishTransaction = false switch transaction.transactionState { case .purchased, .restored: completedPurchases.append(transaction.payment.productIdentifier) shouldFinishTransaction = true case .failed: shouldFinishTransaction = true case .deferred, .purchasing: break @unknown default: break } if shouldFinishTransaction { SKPaymentQueue.default().finishTransaction(transaction) DispatchQueue.main.async { self.purchaseCompletionHandler?(transaction) self.purchaseCompletionHandler = nil } } } if !completedPurchases.isEmpty { UserDefaults.standard.setValue(completedPurchases, forKey: userDefaultsKey) } } } extension Store: SKProductsRequestDelegate { func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { let loadedProducts = response.products let invalidProducts = response.invalidProductIdentifiers guard !loadedProducts.isEmpty else { print("Cloud not load the products!") if !invalidProducts.isEmpty { print("Invalid Products found: \(invalidProducts)") } productsRequest = nil return } // Cache the fetched products fetchedProducts = loadedProducts // Notifi anyone waiting on the product load DispatchQueue.main.async { self.fetchCompletionHandler?(loadedProducts) self.fetchCompletionHandler = nil self.productsRequest = nil } } }estructura Receta()
import Foundation import StoreKit struct Recipe: Hashable { let id: String let title: String let description: String var isLocked: Bool var price: String? let locale: Locale let imageName: String lazy var formatter: NumberFormatter = { let nf = NumberFormatter() nf.numberStyle = .currency nf.locale = locale return nf }() init(product: SKProduct, isLocked: Bool = true) { self.id = product.productIdentifier self.title = product.localizedTitle self.description = product.localizedDescription self.isLocked = isLocked self.locale = product.priceLocale self.imageName = product.productIdentifier if isLocked { self.price = formatter.string(from: product.price) } } }esta es mi estructura con pantalla de suscripción y botón de suscripción
import SwiftUI import Foundation import StoreKit struct Te: View { @ObservedObject var store = Store() var body: some View { ZStack { // After paying for the subscription, the subscription window disappears and the ContentViev() structure appears ContentView() VStack { ZStack(alignment: .center) { Image("subs") .resizable() .overlay(Color.black.opacity(0.6)) .frame(height: 600) .blur(radius: 15) .padding(.top) VStack { Text("ALL ACCESS") .font(.system(size: 32)) .fontWeight(.bold) .foregroundColor(.white) .multilineTextAlignment(.center) .padding(.bottom, 1) Text("UNLOCK ALL ACCESS") .foregroundColor(.white) .font(.system(size: 14)) .multilineTextAlignment(.center) .padding(.horizontal,35) VStack(alignment: .leading) { HStack { Image(systemName: "checkmark.seal") .resizable() .scaledToFit() .frame(width: 25, height: 25) .foregroundColor(.white) Text("Ads") .foregroundColor(.white) } HStack { Image(systemName: "checkmark.seal") .resizable() .scaledToFit() .frame(width: 25, height: 25) .foregroundColor(.white) Text("Item") .foregroundColor(.white) } HStack { Image(systemName: "checkmark.seal") .resizable() .scaledToFit() .frame(width: 25, height: 25) .foregroundColor(.white) Text("New") .foregroundColor(.white) } }.padding(.top, 50) Button(action: { store.purchaseProduct(store.product(for: "PRODUCT_ID_APP_STORE_CONNECT")!) }, label: { Text("SUBSCRIBE") .fontWeight(.bold) .padding() .padding(.horizontal,45) .background(Color.blue.opacity(0.5)) .foregroundColor(Color.white) .cornerRadius(10) }) .padding(.top,45) .padding(.bottom, 25) }.padding(.top,5) } } } } }Después de pagar la suscripción, la ventana de suscripción debería desaparecer y la estructura ContentView () se mostrará en su lugar. Si conoce las suscripciones con renovación automática, mire mi código, tal vez cometí un error en alguna parte. Gracias por cualquier ayuda