内购价格随地区变化

This commit is contained in:
zeng 2025-07-19 13:57:19 +08:00
parent ee36da46d3
commit 01eb1c6c6a
3 changed files with 161 additions and 31 deletions

View File

@ -14,9 +14,71 @@ class SPWalletAPI: NSObject {
} }
/// ///
static func requestPayTemplate(completer: ((_ model: SPPayTemplateModel?) -> Void)?) { static func requestPayTemplate(isLoding: Bool = false, isToast: Bool = true, completer: ((_ model: SPPayTemplateModel?) -> Void)?) {
if isLoding {
SPHUD.show()
}
_requestPayTemplate(isToast: isToast) { model in
guard let model = model else {
if isLoding {
SPHUD.dismiss()
}
completer?(nil)
return
}
var productIdArr: [String] = []
model.list_sub_vip?.forEach { item in
productIdArr.append(SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
}
model.list_coins?.forEach { item in
productIdArr.append(SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
}
SPIAPManager.manager.requestProductList(productIdArr: productIdArr) { products in
if isLoding {
SPHUD.dismiss()
}
var newCoinList: [SPPayTemplateItem] = []
var newVipList: [SPPayTemplateItem] = []
model.list_coins?.forEach { item in
let productId = SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
for product in products {
if productId == product.productIdentifier {
item.price = product.price.stringValue
item.currency = product.priceLocale.currencySymbol
newCoinList.append(item)
break
}
}
}
model.list_sub_vip?.forEach { item in
let productId = SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
for product in products {
if productId == product.productIdentifier {
item.price = product.price.stringValue
item.currency = product.priceLocale.currencySymbol
newVipList.append(item)
break
}
}
}
model.list_coins = newCoinList
model.list_sub_vip = newVipList
completer?(model)
}
}
}
private static func _requestPayTemplate(isToast: Bool = true, completer: ((_ model: SPPayTemplateModel?) -> Void)?) {
var param = SPNetworkParameters(path: "/paySettingsV3") var param = SPNetworkParameters(path: "/paySettingsV3")
param.method = .get param.method = .get
param.isToast = isToast
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPPayTemplateModel>) in SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPPayTemplateModel>) in
completer?(response.data) completer?(response.data)

View File

@ -6,6 +6,7 @@
// //
import UIKit import UIKit
import StoreKit
class SPIAPManager: NSObject { class SPIAPManager: NSObject {
typealias CompletionHandler = ((_ finish: Bool) -> Void) typealias CompletionHandler = ((_ finish: Bool) -> Void)
@ -18,6 +19,8 @@ class SPIAPManager: NSObject {
/// ///
private var completionHandler: CompletionHandler? private var completionHandler: CompletionHandler?
private var productListHandler: ((_ products: [SKProduct]) -> Void)?
private lazy var iapManager: JXIAPManager = { private lazy var iapManager: JXIAPManager = {
let manager = JXIAPManager() let manager = JXIAPManager()
manager.delegate = self manager.delegate = self
@ -119,6 +122,17 @@ class SPIAPManager: NSObject {
} }
} }
func requestProductList(productIdArr: [String], completer: ((_ products: [SKProduct]) -> Void)?) {
self.productListHandler = completer
self.iapManager.requestProductList(productIdArr: productIdArr)
}
func getProductId(templateId: String?) -> String? {
guard let templateId = templateId else { return nil }
return SPIAPManager.IAPPrefix + templateId
}
} }
//MARK: -------------- JXIAPManagerDelegate -------------- //MARK: -------------- JXIAPManagerDelegate --------------
@ -182,6 +196,13 @@ extension SPIAPManager: JXIAPManagerDelegate {
self.completionHandler?(false) self.completionHandler?(false)
} }
func jx_iapPayGotProducts(products: [SKProduct]) {
self.productListHandler?(products)
self.productListHandler = nil
}
} }
extension SPIAPManager { extension SPIAPManager {

View File

@ -10,7 +10,7 @@ import StoreKit
@objc protocol JXIAPManagerDelegate { @objc protocol JXIAPManagerDelegate {
/// ///
@objc optional func jx_iapPayGotProducts(productIds: [String]) @objc optional func jx_iapPayGotProducts(products: [SKProduct])
/// ///
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?) @objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?)
/// ///
@ -34,19 +34,29 @@ import StoreKit
case cancelled case cancelled
/// ///
case noProduct case noProduct
} }
class JXIAPManager: NSObject { class JXIAPManager: NSObject {
enum OperationType {
case idle
case buy
case request
}
static let manager: JXIAPManager = JXIAPManager() static let manager: JXIAPManager = JXIAPManager()
weak var delegate: JXIAPManagerDelegate? weak var delegate: JXIAPManagerDelegate?
///
private var operationType = OperationType.idle
private var payment: SKPayment? private var payment: SKPayment?
private var product: SKProduct? private var product: SKProduct?
private var productId: String? private var productId: String?
private var discount: SKPaymentDiscount?
private var orderId: String? private var orderId: String?
private var applicationUsername: String? { private var applicationUsername: String? {
get { get {
@ -80,10 +90,47 @@ class JXIAPManager: NSObject {
SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(self)
} }
func start(productId: String, orderId: String) { func showCodeRedemption() {
SKPaymentQueue.default().presentCodeRedemptionSheet()
}
func requestProductList(productIdArr: [String]) {
guard self.operationType == .idle else { return }
self.operationType = .request
let set = Set(productIdArr)
let productsRequest = SKProductsRequest(productIdentifiers: set)
productsRequest.delegate = self
productsRequest.start()
}
// ///
// func buyProduct(product: SKProduct, orderId: String, discount: SKPaymentDiscount? = nil) {
// guard self.operationType == .idle else { return }
// self.operationType = .buy
//
// self.product = product
// self.orderId = orderId
//
// //
// let payment = SKMutablePayment(product: product)
// payment.applicationUsername = applicationUsername
// if let discount = discount {
// payment.paymentDiscount = discount
// }
//
// //
// SKPaymentQueue.default().add(payment)
// }
func start(productId: String, orderId: String, discount: SKPaymentDiscount? = nil) {
guard self.operationType == .idle else { return }
self.operationType = .buy
self.product = nil self.product = nil
self.productId = productId self.productId = productId
self.orderId = orderId self.orderId = orderId
self.discount = discount
let set = Set([productId]) let set = Set([productId])
let productsRequest = SKProductsRequest(productIdentifiers: set) let productsRequest = SKProductsRequest(productIdentifiers: set)
@ -98,9 +145,13 @@ class JXIAPManager: NSObject {
// //
let payment = SKMutablePayment(product: product) let payment = SKMutablePayment(product: product)
payment.applicationUsername = applicationUsername payment.applicationUsername = applicationUsername
spLog(message: payment.applicationUsername) if let discount = self.discount {
payment.paymentDiscount = discount
self.discount = nil
}
self.payment = payment self.payment = payment
// //
SKPaymentQueue.default().add(payment) SKPaymentQueue.default().add(payment)
} }
@ -110,6 +161,13 @@ class JXIAPManager: NSObject {
//MARK: -------------- SKProductsRequestDelegate -------------- //MARK: -------------- SKProductsRequestDelegate --------------
extension JXIAPManager: SKProductsRequestDelegate { extension JXIAPManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if self.operationType == .request {
DispatchQueue.main.async {
self.delegate?.jx_iapPayGotProducts?(products: response.products)
}
self.operationType = .idle
} else if self.operationType == .buy {
guard let product = response.products.first else { guard let product = response.products.first else {
DispatchQueue.main.async { DispatchQueue.main.async {
if let productId = self.productId { if let productId = self.productId {
@ -123,6 +181,8 @@ extension JXIAPManager: SKProductsRequestDelegate {
self.buyProduct() self.buyProduct()
} }
}
} }
//MARK: -------------- SKPaymentTransactionObserver -------------- //MARK: -------------- SKPaymentTransactionObserver --------------
@ -131,7 +191,6 @@ extension JXIAPManager: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions { for transaction in transactions {
spLog(message: "transactionState = \(transaction.transactionState)")
switch transaction.transactionState { switch transaction.transactionState {
case .purchased: case .purchased:
DispatchQueue.main.async { DispatchQueue.main.async {
@ -171,33 +230,21 @@ extension JXIAPManager: SKPaymentTransactionObserver {
extension JXIAPManager { extension JXIAPManager {
private func completeTransaction(transaction: SKPaymentTransaction) { 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
// }
spLog(message: "transactionDate = \(String(describing: transaction.transactionDate))")
spLog(message: "nowDate = \(Date())")
spLog(message: "productIdentifier = \(transaction.payment.productIdentifier)")
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
self.productId = nil
guard let receiptURL = Bundle.main.appStoreReceiptURL else { return } guard let receiptURL = Bundle.main.appStoreReceiptURL else { return }
let receiptData = NSData(contentsOf: receiptURL) let receiptData = NSData(contentsOf: receiptURL)
guard let encodeStr = receiptData?.base64EncodedString(options: .endLineWithLineFeed) else { return } guard let encodeStr = receiptData?.base64EncodedString(options: .endLineWithLineFeed) else { return }
guard let transactionIdentifier = transaction.transactionIdentifier else { return } guard let transactionIdentifier = transaction.transactionIdentifier else { return }
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
self.operationType = .idle
self.productId = nil
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier) self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
} }
private func failedTransaction(transaction: SKPaymentTransaction) { private func failedTransaction(transaction: SKPaymentTransaction) {
self.operationType = .idle
let error = transaction.error as? SKError let error = transaction.error as? SKError
guard let productId = self.productId else { return } guard let productId = self.productId else { return }
self.productId = nil self.productId = nil