//
// RechargeManager.swift
// FastMeow
//
// Created by caoyicheng on 2022/2/26.
//
import UIKit
import StoreKit
enum SIAPPurchType {
case Success // 购买成功
case Failed // 购买失败
case Cancle // 取消购买
case VerFailed // 订单校验失败
case VerSuccess // 订单校验成功
case NotAllow // 不允许内购
}
private let RechargeInstance = RechargeManager()
class RechargeManager: NSObject, SKPaymentTransactionObserver, SKProductsRequestDelegate {
typealias RechargeManagerBlock = (_ type: SIAPPurchType, _ data: Data?) -> Void
var statusBlock: RechargeManagerBlock!
var purchID: String!
// MARK: ======================================生命周期========================================
class var share: RechargeManager {
let obj = RechargeInstance
obj.initAction()
return obj
}
// MARK: 初始化
@objc func initAction() {
SKPaymentQueue.default().add(self)
}
// MARK: 开始内购
func startPurchWithID(purchID: String, completeHandle: @escaping RechargeManagerBlock) {
if SKPaymentQueue.canMakePayments() {
self.purchID = purchID
self.statusBlock = completeHandle
let request = SKProductsRequest.init(productIdentifiers: [purchID])
request.delegate = self
request.start()
} else {
completeHandle(.NotAllow, nil)
}
}
// MARK: 交易结束
func completeTransaction(transaction: SKPaymentTransaction) {
let productIdentifier = transaction.payment.productIdentifier
if productIdentifier.count > 0 {
// 向自己的服务器验证购买凭证
}
self.verifyPurchaseWithPaymentTransaction(transaction: transaction, isTestServer: false)
}
// MARK: 验证交易
func verifyPurchaseWithPaymentTransaction(transaction: SKPaymentTransaction, isTestServer: Bool) {
let recepitURL = Bundle.main.appStoreReceiptURL
do {
let receipt = try Data(contentsOf: recepitURL!)
// 购买成功
self.statusBlock(.Success, receipt)
// 购买成功将交易凭证发送给服务端进行再次校验
self.toServiceVerifyPurchaseWithPaymentTransaction(receipt: receipt, transaction: transaction, isTestServer: false)
} catch {
// 交易失败
self.statusBlock(.Failed, nil)
}
}
// MARK: 再次向服务器验证交易
func toServiceVerifyPurchaseWithPaymentTransaction(receipt: Data, transaction: SKPaymentTransaction, isTestServer: Bool) {
do {
let requestContents = ["receipt-data" : receipt.base64EncodedString()]
let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: .prettyPrinted)
let serverString = isTestServer ? "https://sandbox.itunes.apple.com/verifyReceipt" : "https://buy.itunes.apple.com/verifyReceipt"
let storeURL = URL.init(string: serverString)
var storeRequest = URLRequest.init(url: storeURL!)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = requestData
URLSession.shared.dataTask(with: storeRequest) { responseData, response, connectionError in
if connectionError != nil {
// 无法连接服务器,购买校验失败
self.statusBlock(.VerFailed, nil)
} else {
do {
try JSONSerialization.jsonObject(with: responseData!, options: .mutableContainers)
let jsonResponse = try JSONSerialization.jsonObject(with: responseData!, options: .mutableContainers) as! [String : Any]
// 先验证正式服务器,如果正式服务器返回21007再去苹果测试服务器验证,沙盒测试环境苹果用的是测试服务器
let status = String.init(format: "%@", jsonResponse["status"] as! CVarArg)
if status == "21007" {
self.verifyPurchaseWithPaymentTransaction(transaction: transaction, isTestServer: true)
} else {
self.statusBlock(.VerSuccess, nil)
}
} catch {
// 苹果服务器校验数据返回为空校验失败
self.statusBlock(.VerFailed, nil)
}
}
}
} catch {
// 交易验证失败
self.statusBlock(.VerFailed, nil)
}
}
// MARK: 交易失败
func failedTransaction(transaction: SKPaymentTransaction) {
self.statusBlock(.Failed, nil)
SKPaymentQueue.default().finishTransaction(transaction)
}
// MARK: ======================================代理方法========================================
// MARK: 交易状态
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transtion in transactions {
if transtion.transactionState == .purchased {
// 购买成功
self.completeTransaction(transaction: transtion)
} else if transtion.transactionState == .purchasing {
// 正在购买
} else if transtion.transactionState == .restored {
// 恢复
SKPaymentQueue.default().finishTransaction(transtion)
} else if transtion.transactionState == .failed {
// 购买失败
self.failedTransaction(transaction: transtion)
} else {
}
}
}
// MARK: 请求查看存在的产品
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let products = response.products
if products.count == 0 {
print("没有商品")
return
}
var product: SKProduct?
for item in products {
if item.productIdentifier == self.purchID {
product = item
break
}
}
if product != nil {
print("产品信息:")
print(product)
let payment = SKPayment.init(product: product!)
SKPaymentQueue.default().add(payment)
}
}
}
参考文章
https://www.jianshu.com/p/2247f3b36be3