// // IAPManager.swift // QuickLocation // // Created by 八条 on 2026/7/3. // import StoreKit import RxSwift class IAPManager: NSObject { static let shared = IAPManager() private let disposeBag = DisposeBag() private var currentGoodsId: String = "" private var purchaseCompletion: ((Bool, String?) -> Void)? func startObserving() { SKPaymentQueue.default().add(self) } func purchase(goodsId: String, completion: @escaping (Bool, String?) -> Void) { currentGoodsId = goodsId purchaseCompletion = completion let request = SKProductsRequest(productIdentifiers: [goodsId]) request.delegate = self request.start() } } // MARK: - SKProductsRequestDelegate extension IAPManager: SKProductsRequestDelegate { func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { guard let product = response.products.first else { purchaseCompletion?(false, "商品不可用") return } SKPaymentQueue.default().add(SKPayment(product: product)) } } // MARK: - SKPaymentTransactionObserver extension IAPManager: SKPaymentTransactionObserver { func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for tx in transactions { switch tx.transactionState { case .purchased: verifyReceipt(transaction: tx) case .failed: queue.finishTransaction(tx) let msg = tx.error?.localizedDescription ?? "支付失败" purchaseCompletion?(false, msg) default: break } } } private func verifyReceipt(transaction: SKPaymentTransaction) { guard let receiptURL = Bundle.main.appStoreReceiptURL, let receiptData = try? Data(contentsOf: receiptURL) else { SKPaymentQueue.default().finishTransaction(transaction) purchaseCompletion?(false, "获取凭证失败") return } let receipt = receiptData.base64EncodedString() let txId = transaction.transactionIdentifier ?? "" OrderService.appleNotify( receipt: receipt, productId: currentGoodsId, transactionId: txId ).subscribe(onNext: { [weak self] _ in SKPaymentQueue.default().finishTransaction(transaction) self?.purchaseCompletion?(true, nil) }, onError: { [weak self] error in SKPaymentQueue.default().finishTransaction(transaction) self?.purchaseCompletion?(false, error.localizedDescription) }).disposed(by: disposeBag) } }