186 lines
5.8 KiB
Swift
186 lines
5.8 KiB
Swift
//
|
||
// JXIAPManager.swift
|
||
// BoJia
|
||
//
|
||
// Created by 火山传媒 on 2024/6/3.
|
||
//
|
||
|
||
import UIKit
|
||
import StoreKit
|
||
|
||
@objc protocol JXIAPManagerDelegate {
|
||
/// 购买成功
|
||
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?)
|
||
/// 购买失败
|
||
@objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?)
|
||
/// 恢复商品(仅限永久有效商品)
|
||
@objc optional func iapPayRestore(productIds: [String], transactionIds: [String])
|
||
// /// 加载
|
||
// @objc optional func iapPayShowHud()
|
||
// /// 系统错误
|
||
// @objc optional func iapSysWrong()
|
||
// /// 验证成功
|
||
// @objc optional func verifySuccess()
|
||
// /// 验证失败
|
||
// @objc optional func verifyFailed()
|
||
}
|
||
|
||
@objc enum JXIAPManagerCode: Int {
|
||
///未知错误
|
||
case unknown
|
||
///取消交易
|
||
case cancelled
|
||
///没有商品
|
||
case noProduct
|
||
}
|
||
|
||
class JXIAPManager: NSObject {
|
||
|
||
|
||
static let manager: JXIAPManager = JXIAPManager()
|
||
|
||
weak var delegate: JXIAPManagerDelegate?
|
||
|
||
private var payment: SKPayment?
|
||
|
||
private var product: SKProduct?
|
||
private var productId: String?
|
||
|
||
private var discount: SKPaymentDiscount?
|
||
private var orderId: String?
|
||
private var applicationUsername: String? {
|
||
get {
|
||
return orderId
|
||
}
|
||
}
|
||
|
||
|
||
override init() {
|
||
super.init()
|
||
SKPaymentQueue.default().add(self)
|
||
}
|
||
|
||
|
||
func start(productId: String, orderId: String, discount: SKPaymentDiscount? = nil) {
|
||
self.product = nil
|
||
self.productId = productId
|
||
self.orderId = orderId
|
||
self.discount = discount
|
||
|
||
let set = Set([productId])
|
||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||
productsRequest.delegate = self
|
||
productsRequest.start()
|
||
}
|
||
|
||
/// 购买商品
|
||
private func buyProduct() {
|
||
guard let product = self.product else { return }
|
||
|
||
// 要购买商品,开个小票
|
||
let payment = SKMutablePayment(product: product)
|
||
payment.applicationUsername = applicationUsername
|
||
if let discount = self.discount {
|
||
payment.paymentDiscount = discount
|
||
self.discount = nil
|
||
}
|
||
|
||
self.payment = payment
|
||
|
||
// 去收银台排队,准备购买
|
||
SKPaymentQueue.default().add(payment)
|
||
}
|
||
|
||
}
|
||
|
||
//MARK: -------------- SKProductsRequestDelegate --------------
|
||
extension JXIAPManager: SKProductsRequestDelegate {
|
||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||
guard let product = response.products.first else {
|
||
DispatchQueue.main.async {
|
||
if let productId = self.productId {
|
||
self.productId = nil
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct, msg: nil)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
self.product = product
|
||
|
||
self.buyProduct()
|
||
|
||
}
|
||
}
|
||
|
||
//MARK: -------------- SKPaymentTransactionObserver --------------
|
||
extension JXIAPManager: SKPaymentTransactionObserver {
|
||
///购买回调
|
||
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||
|
||
for transaction in transactions {
|
||
switch transaction.transactionState {
|
||
case .purchased:
|
||
DispatchQueue.main.async {
|
||
self.completeTransaction(transaction: transaction)
|
||
}
|
||
SKPaymentQueue.default().finishTransaction(transaction)
|
||
|
||
case .failed:
|
||
DispatchQueue.main.async {
|
||
self.failedTransaction(transaction: transaction)
|
||
}
|
||
SKPaymentQueue.default().finishTransaction(transaction)
|
||
// case .restored:
|
||
// self.restoreTransaction(transaction: transaction)
|
||
|
||
case .purchasing:
|
||
break
|
||
default:
|
||
SKPaymentQueue.default().finishTransaction(transaction)
|
||
break
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
// func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
|
||
// return true
|
||
// }
|
||
|
||
/// 恢复购买回调
|
||
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
|
||
|
||
}
|
||
|
||
}
|
||
|
||
extension JXIAPManager {
|
||
private func completeTransaction(transaction: SKPaymentTransaction) {
|
||
guard let receiptURL = Bundle.main.appStoreReceiptURL else { return }
|
||
let receiptData = NSData(contentsOf: receiptURL)
|
||
guard let encodeStr = receiptData?.base64EncodedString(options: .endLineWithLineFeed) else { return }
|
||
guard let transactionIdentifier = transaction.transactionIdentifier else { return }
|
||
|
||
|
||
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
|
||
self.productId = nil
|
||
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
|
||
|
||
}
|
||
|
||
private func failedTransaction(transaction: SKPaymentTransaction) {
|
||
let error = transaction.error as? SKError
|
||
guard let productId = self.productId else { return }
|
||
self.productId = nil
|
||
|
||
switch error?.code {
|
||
case SKError.paymentCancelled:
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled, msg: error?.localizedDescription)
|
||
default:
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown, msg: error?.localizedDescription)
|
||
}
|
||
|
||
}
|
||
}
|