199 lines
6.4 KiB
Swift
199 lines
6.4 KiB
Swift
//
|
||
// JXIAPManager.swift
|
||
// BoJia
|
||
//
|
||
// Created by 火山传媒 on 2024/6/3.
|
||
//
|
||
|
||
import UIKit
|
||
import StoreKit
|
||
|
||
@objc protocol JXIAPManagerDelegate {
|
||
/// 获取到可购买商品列表
|
||
@objc optional func jx_iapPayGotProducts(productIds: [String])
|
||
/// 购买成功
|
||
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?)
|
||
/// 购买失败
|
||
@objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode)
|
||
/// 恢复商品(仅限永久有效商品)
|
||
@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 orderId: String?
|
||
private var applicationUsername: String? {
|
||
get {
|
||
let id = "00000000-0000-0000-0000-000000000000"
|
||
guard let orderId = orderId else { return nil }
|
||
var string = ""
|
||
for i in 0..<orderId.length() {
|
||
if i == 12 || i == 16 || i == 20 || i == 24 {
|
||
string.insert("-", at: string.startIndex)
|
||
}
|
||
let s = orderId[orderId.index(orderId.endIndex, offsetBy: -(i + 1))]
|
||
string.insert(s, at: string.startIndex)
|
||
}
|
||
|
||
let length = id.length()
|
||
let stringLength = string.length()
|
||
|
||
if stringLength <= length {
|
||
let range = NSRange(location: length - string.length(), length: string.length())
|
||
return id.ocString().replacingCharacters(in: range, with: string)
|
||
} else {
|
||
return string
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
override init() {
|
||
super.init()
|
||
SKPaymentQueue.default().add(self)
|
||
}
|
||
|
||
func start(productId: String, orderId: String) {
|
||
self.product = nil
|
||
self.productId = productId
|
||
self.orderId = orderId
|
||
|
||
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
|
||
spLog(message: payment.applicationUsername)
|
||
|
||
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 {
|
||
self.delegate?.jx_iapPayFailed?(productId: self.productId, code: .noProduct)
|
||
}
|
||
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) {
|
||
//自动续费
|
||
if let _ = transaction.original, transaction.payment.applicationUsername == nil {
|
||
return
|
||
}
|
||
//重新开通自动续费
|
||
if let _ = transaction.original, transaction.payment.applicationUsername != nil {
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown)
|
||
return
|
||
}
|
||
|
||
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 }
|
||
|
||
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
|
||
}
|
||
|
||
private func failedTransaction(transaction: SKPaymentTransaction) {
|
||
let error = transaction.error as? SKError
|
||
switch error?.code {
|
||
case SKError.paymentCancelled:
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled)
|
||
default:
|
||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown)
|
||
}
|
||
}
|
||
}
|