feat: 优化 PIIAPRegulate

This commit is contained in:
eggmanQQQ
2024-09-24 18:02:05 +08:00
parent 6ba054c694
commit 4d46e1505c

View File

@@ -15,12 +15,9 @@ typealias RenewalState = StoreKit.Product.SubscriptionInfo.RenewalState
enum PIStoreError: Error { enum PIStoreError: Error {
// //
case failedVerification case failedVerification
case noProduct case noProduct
} }
@objc public enum StoreConditionResult: Int64 { // @objc public enum StoreConditionResult: Int64 { //
@@ -43,32 +40,26 @@ public class PIIAPRegulate: NSObject {
var updateListenerTask: Task<Void, Error>? = nil // var updateListenerTask: Task<Void, Error>? = nil //
var transactionMap :[String:Transaction] // Idmap var transactionMap :[String:Transaction] = [:]// Idmap
var name: String = "iosStore" // @objc public static let shared = PIIAPRegulate()
@objc public static let shared = {
let instance = PIIAPRegulate()
return instance
}()
private override init() { // private private override init() { // private
transactionMap = [:] //
super.init() super.init()
Task { self.updateListenerTask = listenForTransactions()
updateListenerTask = listenForTransactions()
}
} }
func triggerConditionBlock(_ state: StoreConditionResult, _ param: [String: Any]? = nil) {
if let ConditionBlock = ConditionBlock {
ConditionBlock(state, param)
}
}
// 退 // 退
@objc public func refunRequest(view: UIView,transactionId:UInt64) async{ @objc public func refunRequest(view: UIView,transactionId:UInt64) async {
do { do {
if let scene = await view.window?.windowScene{ if let scene = await view.window?.windowScene{
try await Transaction.beginRefundRequest(for:transactionId , in: scene) _ = try await Transaction.beginRefundRequest(for:transactionId , in: scene)
} }
}catch{ }catch{
print("iap error") print("iap error")
@@ -77,70 +68,43 @@ public class PIIAPRegulate: NSObject {
// //
@objc public func demandCommodityThing(productId:String, uuid: String) async throws { @objc public func demandCommodityThing(productId:String, uuid: String) async throws {
if(ConditionBlock != nil ){ triggerConditionBlock(.start)
ConditionBlock(StoreConditionResult.start,nil)
}
do { do {
let list:[String] = [productId] let list = [productId]
let storeProducts = try await Product.products(for: Set.init(list)) let storeProducts = try await Product.products(for: Set(list))
guard let product = storeProducts.first else {
// triggerConditionBlock(.noProduct)
throw PIStoreError.noProduct
if storeProducts.count > 0 {
try await purchase(storeProducts[0],uuid)
}else {
print("iap: no found product")
if(ConditionBlock != nil ){
ConditionBlock(StoreConditionResult.noProduct,nil)
}
throw PIStoreError.noProduct //
} }
_ = try await purchase(product, uuid)
} catch { } catch {
print("Failed product request from the App Store server: \(error)") triggerConditionBlock(.noProduct)
if(ConditionBlock != nil ){ throw PIStoreError.noProduct
ConditionBlock(StoreConditionResult.noProduct,nil)
}
throw PIStoreError.noProduct //
} }
} }
// //
private func purchase(_ product: Product, _ uuid: String) async throws -> Transaction? { private func purchase(_ product: Product, _ uuid: String) async throws -> Transaction? {
if(ConditionBlock != nil ){ triggerConditionBlock(.pay)
ConditionBlock(StoreConditionResult.pay,nil)
}
guard let curUUID = UUID.init(uuidString: uuid) else{ guard let curUUID = UUID.init(uuidString: uuid) else{
triggerConditionBlock(.failedVerification)
if(ConditionBlock != nil ){
ConditionBlock(StoreConditionResult.failedVerification,nil)
}
return nil return nil
} }
let getUUID = Product.PurchaseOption.appAccountToken(curUUID)
let result = try await product.purchase(options: [getUUID]) let result = try await product.purchase(options: [.appAccountToken(curUUID)])
switch result { switch result {
case .success(let verification): // case .success(let verification): //
let transaction = try await verifiedAndAccomplish(verification) return try await verifiedAndAccomplish(verification)
return transaction
case .userCancelled: // case .userCancelled: //
if(ConditionBlock != nil ){ triggerConditionBlock(.userCancelled)
ConditionBlock(StoreConditionResult.userCancelled,nil)
}
return nil
case .pending: // case .pending: //
if(ConditionBlock != nil ){ triggerConditionBlock(.pending)
ConditionBlock(StoreConditionResult.pending,nil)
}
return nil
default: default:
if(ConditionBlock != nil ){ triggerConditionBlock(.unowned)
ConditionBlock(StoreConditionResult.unowned,nil)
}
return nil
} }
return nil
} }
// //
@@ -149,9 +113,7 @@ public class PIIAPRegulate: NSObject {
switch result { switch result {
case .unverified: case .unverified:
//StoreKit parses the JWS, but it fails verification. //StoreKit parses the JWS, but it fails verification.
if(ConditionBlock != nil ){ triggerConditionBlock(.failedVerification)
ConditionBlock(StoreConditionResult.failedVerification,nil)
}
throw PIStoreError.failedVerification throw PIStoreError.failedVerification
case .verified(let safe): case .verified(let safe):
//The result is verified. Return the unwrapped value. //The result is verified. Return the unwrapped value.
@@ -195,53 +157,60 @@ public class PIIAPRegulate: NSObject {
break break
} }
} catch let error { } catch let error {
print("error:----\(error)") print("error:----\(error)")
} }
} }
//Transaction.latest(for: "pid")
} }
// //
@objc public func verifyBusinessAccomplish(transaction:String) async{ // @objc public func verifyBusinessAccomplish(transaction:String) async {
if(transactionMap[transaction] != nil){ // if(transactionMap[transaction] != nil){
await transactionMap[transaction]!.finish() // await transactionMap[transaction]!.finish()
transactionMap.removeValue(forKey: transaction) // transactionMap.removeValue(forKey: transaction)
print("verifyBusinessFinish end") // print("verifyBusinessFinish end")
}else { // }else {
await getAllBusiness(transactionId: transaction) // await getAllBusiness(transactionId: transaction)
// }
// }
@objc public func verifyBusinessAccomplish(transactionID: String, completionHandler: @escaping (Bool, Error?) -> Void) {
if let transaction = transactionMap[transactionID] {
Task {
await transaction.finish()
transactionMap.removeValue(forKey: transactionID)
completionHandler(true, nil) //
}
} else {
Task {
await getAllBusiness(transactionId: transactionID)
completionHandler(false, nil) //
}
} }
} }
@MainActor @MainActor
func uploadServer(for transactionId:UInt64) async { func uploadServer(for transactionId:UInt64) async {
let dic :Dictionary<String,Any> = ["transactionId":transactionId] let dic :Dictionary<String,Any> = ["transactionId":transactionId]
if(ConditionBlock != nil ){ triggerConditionBlock(.verifiedServer, dic)
ConditionBlock(StoreConditionResult.verifiedServer,dic)
}
} }
// //
func listenForTransactions() -> Task<Void, Error> { func listenForTransactions() -> Task<Void, Error> {
return Task.detached { return Task.detached {
//Iterate through any transactions that don't come from a direct call to `purchase()`. for await result in Transaction.updates {
// update unfinished?
for await result in Transaction.updates { //
do { do {
print("iap: updates") let resultId = try result.payloadValue.id
print("result:\(result)") if !self.transactionMap.keys.contains(String(resultId)) {
try await self.verifiedAndAccomplish(result) _ = try await self.verifiedAndAccomplish(result)
}
} catch { } catch {
//StoreKit has a transaction that fails verification. Don't deliver content to the user. //
print("Transaction failed verification") print("Error: \(error)")
} }
} }
} }
} }
//广 //广
func Promotion() async -> [SKProduct]?{ func Promotion() async -> [SKProduct]?{
let promotion = SKProductStorePromotionController() let promotion = SKProductStorePromotionController()