0.3 C
New York
Sunday, February 23, 2025

ios – Is that this the best way to use StoreKit2


I am new to StoreKit2. Is that this the best way to use StoreKit2? I am I implementing buying of subscriptions correctly.

This is my PurchaseManager

import StoreKit
import AmplitudeSwift

class PurchaseManager: ObservableObject {
    // A printed property to carry accessible merchandise
    @Printed var merchandise: [Product] = []
    // A printed property to trace the standing of transactions
    @Printed var transactionState: String = "Idle"
    
    // A set of product identifiers
    personal let productIdentifiers: Set = [
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID,
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID_50_OFF,
        PaymentHandler.sharedInstance.MONTHLY_PRODUCT_ID
    ]
    
    // Shared occasion for use all through the app
    static let shared = PurchaseManager()
    
    personal init() {}
    
    // MARK: - Fetch Merchandise from App Retailer
    func fetchProducts() async {
        do {
            let merchandise = strive await Product.merchandise(for: productIdentifiers)
            self.merchandise = merchandise
        } catch {
            print("Did not fetch merchandise: (error.localizedDescription)")
        }
    }
    
    // MARK: - Deal with Buy
    func purchaseProduct(product: Product, supply: String) async -> Bool {
        do {
            // Begin the acquisition
            let consequence = strive await product.buy()
            
            // Deal with the results of the acquisition
            change consequence {
            case .success(let verificationResult):
                change verificationResult {
                case .verified(let transaction):
                    self.transactionState = "Buy Profitable"
                    await transaction.end()
                    return true
                case .unverified(let transaction, let error):
                    self.transactionState = "Buy Unverified: (error.localizedDescription)"
                    await transaction.end()
                    await showMessageWithTitle("Error!", "There was an error processing your buy", .error)
                    return false
                }
            case .userCancelled:
                self.transactionState = "Person cancelled the acquisition."
               
                Amplitude.sharedInstance.monitor(
                    eventType: "payment_cancelled",
                    eventProperties: ["PlanId": product.id, "Source": source]
                )
                
            case .pending:
                self.transactionState = "Buy is pending."
                
                await showMessageWithTitle("Error!", "There was an error processing your buy", .error)
            @unknown default:
                self.transactionState = "Unknown buy consequence."
                
                await showMessageWithTitle("Error!", "There was an error processing your buy", .error)
                
                Amplitude.sharedInstance.monitor(
                    eventType: "payment_failed",
                    eventProperties: ["PlanId": product.id, "Source": source]
                )
                
            }
        } catch {
            self.transactionState = "Buy failed: (error.localizedDescription)"
            
            await showMessageWithTitle("Error!", "There was an error processing your buy", .error)
            
            Amplitude.sharedInstance.monitor(
                eventType: "payment_failed",
                eventProperties: ["PlanId": product.id, "Source": source]
            )
            
        }
        return false
    }
    
    // MARK: - Pay attention for Transaction Updates
    func listenForTransactionUpdates() {
        Activity {
            for await lead to Transaction.updates {
                change consequence {
                case .verified(let transaction):
                    self.transactionState = "Transaction verified: (transaction.productID)"
                    await transaction.end()
                    // Unlock the content material related to the transaction
                case .unverified(let transaction, let error):
                    self.transactionState = "Unverified transaction: (error.localizedDescription)"
                    await transaction.end()
                }
            }
        }
    }
}

This is the place I course of the cost

@MainActor func purchaseProduct(productId: String, plan: String, supply: String, vc: UIViewController) async -> Bool {
        self.loadingIndicator = ThreeBubblesLoadingView()
        self.loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
        vc.view.addSubview(self.loadingIndicator)
        
        NSLayoutConstraint.activate([
            self.loadingIndicator.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor),
            self.loadingIndicator.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor)
        ])
        
        DispatchQueue.fundamental.async {
            Amplitude.sharedInstance.monitor(
                eventType: "payment_started",
                eventProperties: ["Source": source]
            )
        }
        
        Activity {
            await PurchaseManager.shared.fetchProducts()
            let merchandise = PurchaseManager.shared.merchandise
            
            if let selectProduct = merchandise.first(the place: { $0.id == productId }) {
                
               let consequence = await PurchaseManager.shared.purchaseProduct(product: selectProduct, supply: supply)
                
                if (consequence ) {
                    Amplitude.sharedInstance.monitor(
                        eventType: "payment_completed",
                        eventProperties: ["PlanId": productId, "Source": source]
                    )
                    
                    self.loadingIndicator.removeFromSuperview()
                    
                    return await self.buy(
                        vc: vc,
                        productId: selectProduct.id,
                        product:selectProduct.id
                    )
                }
            }
            
            return false
        }

        return false
    }

Am I doing one thing fallacious? Do I’ve to name PurchaseManager.shared.listenForTransactionUpdates() and the place?
?

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles