// // LNPurchaseManagerOld.swift // Lanu // // Created by OneeChan on 2025/12/29. // import Foundation import StoreKit import Foundation /// 充值状态回调 typealias fetchCompletion = (Result<[SKProduct], LNPurchaseError>) -> Void /// 充值管理单例类(StoreKit 1) final class RechargeManager: NSObject { // MARK: - 单例 static let shared = RechargeManager() private override init() { super.init() LNEventDeliver.addObserver(self) } // MARK: - 私有属性 /// 商品信息缓存 private var productCache: [String: SKProduct] = [:] private let lock = NSLock() /// 支付完成回调 private var fetchCompletion: fetchCompletion? /// 监听交易队列 private var paymentQueue: SKPaymentQueue { SKPaymentQueue.default() } // MARK: - 生命周期 /// 启动监听(建议在 AppDelegate 或 SceneDelegate 中调用) private func startObserving() { paymentQueue.add(self) } /// 停止监听(建议在 App 退出时调用) private func stopObserving() { paymentQueue.remove(self) } // MARK: - 公开方法 /// 加载充值商品信息 /// - Parameters: /// - productIds: 商品ID数组 /// - completion: 加载完成回调 func loadRechargeProducts(productIds: [String], completion: fetchCompletion?) { // 过滤空ID let validIds = productIds.filter { !$0.isEmpty } guard !validIds.isEmpty else { completion?(.failure(.productNotFound)) return } // 检查缓存 lock.lock() let cachedProducts = validIds.compactMap { productCache[$0] } lock.unlock() if cachedProducts.count == validIds.count { completion?(.success(cachedProducts)) return } // 从苹果服务器请求商品 fetchCompletion = completion let request = SKProductsRequest(productIdentifiers: Set(validIds)) request.delegate = self request.start() } /// 发起充值支付 /// - Parameters: /// - productId: 商品ID /// - completion: 支付完成回调 func startRecharge(goods: LNPurchaseGoodsVO) { // 检查支付是否可用 guard SKPaymentQueue.canMakePayments() else { notifyPurchaseResult(err: .paymentInvalid) return } // 恢复未完成的交易 restoreUnfinishedTransactions() // 加载商品并发起支付 loadRechargeProducts(productIds: [goods.code]) { [weak self] result in guard let self = self else { return } switch result { case .success(let products): guard let product = products.first else { notifyPurchaseResult(err: .productNotFound) return } LNHttpManager.shared.createPurchase(id: goods.id) { [weak self] res, err in guard let self else { return } guard let res, err == nil else { notifyPurchaseResult(err: .createOrderfailed) return } // 创建支付请求 // 保存当前回调 let payment = SKMutablePayment(product: product) payment.applicationUsername = res.result LNUserDefaults[.purchaseOrderId] = res.result self.paymentQueue.add(payment) } case .failure(let error): notifyPurchaseResult(err: error) } } } /// 恢复未完成的交易 private func restoreUnfinishedTransactions() { paymentQueue.restoreCompletedTransactions() } // MARK: - 私有方法 private func validateReceipt(for transaction: SKPaymentTransaction) { // 1. 获取应用收据 guard let receiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: receiptURL.path) else { notifyPurchaseResult(err: .receiptParseFailed) return } // 2. 读取收据数据 do { let receiptData = try Data(contentsOf: receiptURL) let receiptString = receiptData.base64EncodedString(options: []) let orderId = transaction.payment.applicationUsername ?? LNUserDefaults[.purchaseOrderId, ""] LNHttpManager.shared.verifyPurchase(orderId: orderId, receipt: receiptString) { [weak self] err in guard let self else { return } let success = err == nil if success { notifyPurchaseResult(err: nil) Log.w("充值成功 - 商品ID: \(transaction.payment.productIdentifier)") LNPurchaseManager.shared.reloadWalletInfo() let productId = transaction.payment.productIdentifier if let (type, goods) = LNPurchaseManager.shared.goodsFro(productId) { LNStatisticManager.shared.reportPayment(type: type, amount: goods.coinRechargeAmount, currency: goods.currency, price: goods.amount, orderId: orderId) } } else { notifyPurchaseResult(err: .receiptVerifyFailed) Log.w("充值失败 - 收据验证失败") } // 结束交易 paymentQueue.finishTransaction(transaction) } } catch { Log.w("收据验证失败: \(error)") notifyPurchaseResult(err: .unknownError(error)) } } } extension RechargeManager: LNAccountManagerNotify { func onUserLogin() { startObserving() } func onUserLogout() { stopObserving() } } // MARK: - SKProductsRequestDelegate extension RechargeManager: SKProductsRequestDelegate { func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { // 缓存商品信息 let products = response.products lock.lock() products.forEach { productCache[$0.productIdentifier] = $0 } lock.unlock() // 处理无效商品ID let invalidIds = response.invalidProductIdentifiers if !invalidIds.isEmpty { Log.w("无效的商品ID: \(invalidIds)") } // 回调结果 if !products.isEmpty { // 这里是加载商品的回调,需要匹配原始请求的completion // 注:实际使用时建议通过闭包捕获或使用更优雅的回调管理 fetchCompletion?(.success(products)) } else { Log.w("未找到对应商品") fetchCompletion?(.failure(.productNotFound)) } fetchCompletion = nil } func request(_ request: SKRequest, didFailWithError error: Error) { Log.w("商品请求失败: \(error.localizedDescription)") // 匹配错误类型 fetchCompletion?(.failure(.unknownError(error))) fetchCompletion = nil } } // MARK: - SKPaymentTransactionObserver extension RechargeManager: SKPaymentTransactionObserver { func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { transactions.forEach { transaction in switch transaction.transactionState { case .purchased: // 交易完成,验证收据 validateReceipt(for: transaction) case .failed: // 交易失败 let error = transaction.error as NSError? if error?.code == SKError.paymentCancelled.rawValue { notifyPurchaseResult(err: .paymentCancelled) paymentQueue.finishTransaction(transaction) Log.w("用户取消支付") } else { notifyPurchaseResult(err: .unknownError(transaction.error ?? NSError(domain: "RechargeError", code: -1, userInfo: nil))) Log.w("交易失败: \(transaction.error?.localizedDescription ?? "未知错误")") } case .restored: // 恢复交易 validateReceipt(for: transaction) case .purchasing, .deferred: // 交易中/延迟处理(如家长审核) Log.w("交易状态: \(transaction.transactionState.rawValue)") @unknown default: notifyPurchaseResult(err: .unknownError(NSError(domain: "RechargeError", code: -2, userInfo: nil))) Log.w("未知交易状态") } } } func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { Log.w("恢复交易完成 - 共恢复 \(queue.transactions.count) 笔交易") } func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { Log.w("恢复交易失败: \(error.localizedDescription)") notifyPurchaseResult(err: .unknownError(error)) } } extension RechargeManager { private func notifyPurchaseResult(err: LNPurchaseError?) { LNEventDeliver.notifyEvent { ($0 as? LNPurchaseManagerNotify)?.onUserPurchaseResult(err: err) } } }