Swift IAP 订阅处理所有交易

Swift IAP subscription processing all transactions

我对 swift 中的 IAP 订阅处理有疑问。 我在我的应用程序中使用 IAP 订阅,逻辑完美无缺,我没有任何问题。我想检查处理来自 paymentQueue 的交易。我注意到它正在循环 paymentQueue 中的所有交易,我必须验证所有交易的收据。这是否有必要循环检查所有交易,或者我应该只关注最后一笔交易。最后一笔交易会是最近的一笔交易吗?以下是部分代码的代码片段。

在输出控制台中,我得到以下几行(最后三行循环 140 次): 总交易数 - 140

开始刷新收据...

内部解析收据....

已购买交易

问题:是否需要处理所有的交易(本例中为140)这个140是针对同一个产品的。我可以通过任何方式避免这种循环,从而改进处理。

提前致谢。

extension IAPManager: SKPaymentTransactionObserver {
    
    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        
        print(" Total Transaction Count -  \(queue.transactions.count)")
        for transaction in transactions {
            switch (transaction.transactionState) {
            case .purchased:
                notifyIsPurchased(transaction: transaction)
                SKPaymentQueue.default().finishTransaction(transaction)
                print ("Transaction Purchased")
                break
            case .failed:
                SKPaymentQueue.default().finishTransaction(transaction)
                self.failureBlock?(transaction.error)
                cleanUp()
                break
            case .restored:
                notifyIsPurchased(transaction: transaction)
                SKPaymentQueue.default().finishTransaction(transaction)
                print("restored")
                break
            case .deferred:
                print("defered")
                break
            case .purchasing:
                print("purchasing")
                break
            default:
                break
            }
        }
    }

    private func notifyIsPurchased(transaction: SKPaymentTransaction) {
        refreshSubscriptionsStatus(callback: {
            self.successBlock?()
            self.cleanUp()
        }) { (error) in
            // couldn't verify receipt
            self.failureBlock?(error)
            self.cleanUp()
        }
    }

    func refreshSubscriptionsStatus(callback : @escaping SuccessBlock, failure : @escaping FailureBlock) {
        
        print("Start refreshing reciept...")
        self.refreshSubscriptionSuccessBlock = callback
        self.refreshSubscriptionFailureBlock = failure
        
        guard let receiptUrl = Bundle.main.appStoreReceiptURL else {
            print("No reciept")
            refreshReceipt()
            return
        }
        
        let urlString = "https://sandbox.itunes.apple.com/verifyReceipt"
        //let urlString = "https://buy.itunes.apple.com/verifyReceipt"
        let receiptData = try? Data(contentsOf: receiptUrl).base64EncodedString()
        let requestData = ["receipt-data" : receiptData ?? "", "password" : self.sharedSecret, "exclude-old-transactions" : true] as [String : Any]
        var request = URLRequest(url: URL(string: urlString)!)
        request.httpMethod = "POST"
        request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
        let httpBody = try? JSONSerialization.data(withJSONObject: requestData, options: [])
        request.httpBody = httpBody
        
        URLSession.shared.dataTask(with: request)  { (data, response, error) in
        DispatchQueue.main.async {
            if data != nil {
                if let json = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments){
                    //print (json)
                    self.parseReceipt(json as! Dictionary<String, Any>)
                    return
                }
            } else {
                print("error validating receipt: \(error?.localizedDescription ?? "")")
            }
            self.refreshSubscriptionFailureBlock?(error)
            self.cleanUpRefeshReceiptBlocks()
        }
        }.resume()
    }

    private func parseReceipt(_ json : Dictionary<String, Any>) {
        
        print("Inside Parsing Reciept....")
        
        
        guard let receipts_array = json["latest_receipt_info"] as? [Dictionary<String, Any>] else {
            self.refreshSubscriptionFailureBlock?(nil)
            self.cleanUpRefeshReceiptBlocks()
            return
        }

        process the receipt array and check if it is expired or valid...

    }

无法 100% 保证您 [SKPaymentTransaction] 中的最后一笔交易是您最近的一笔交易,根据 Apple documentation 的记载 transactions 属性 是:

An array of the transactions that were updated.

那里没有明确说明 transactions 已正确排序,尽管数组通常用于顺序很重要的元素。但是您可以通过访问 transactionDate 属性。这是一个例子:

func paymentQueue(_ queue: SKPaymentQueue,
                      updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        let ascendingTransactions = transactions.filter({[=10=].transactionDate != nil})
                                                .sorted(by: {.transactionDate! > [=10=].transactionDate!})
        let latestTransaction = ascendingTransactions.last
        
    }
}