2025-04-29 13:27:40 +08:00

199 lines
6.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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
tmLog(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)
}
}
}