Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

512
Views
Show structure after payment Auto-renewable subscriptions (SwiftUI)

I have a code for auto-renewable subscriptions, how to close the subscription window after paying for the subscription and display the ContentView() structure.

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

structure Recipe()

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

this is my structure with subscribe display and subscribe button

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

After paying for the subscription, the subscription window should disappear and the ContentView () structure will be displayed in its place, if you know about auto-renewable subscriptions, please look at my code, maybe I made a mistake somewhere. Thanks for any help

over 4 years ago · Santiago Trujillo
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!