255 lines
10 KiB
Swift
255 lines
10 KiB
Swift
//
|
||
// MP_IAPManager.swift
|
||
// relax.offline.mp3.music
|
||
//
|
||
// Created by Mr.Zhou on 2024/7/29.
|
||
//
|
||
|
||
import UIKit
|
||
import SwiftyStoreKit
|
||
import StoreKit
|
||
///内部购买项目管理器
|
||
class MP_IAPManager: NSObject {
|
||
///单例
|
||
static let shared = MP_IAPManager()
|
||
///产品ID(根据开关获取)
|
||
var productIdentifiers:[String] = ["1weekvip","1yearvip","lifetimevip"]
|
||
///产品交易信息组
|
||
private var transactions:[PaymentTransaction] = []
|
||
///产品请求(根据ID获取产品信息)
|
||
private var productsRequest:SKProductsRequest?
|
||
///可用产品组
|
||
private var availableProducts:Set<SKProduct> = []
|
||
///调用方案
|
||
private var showHUD:Bool = false
|
||
///是否是VIP
|
||
var isVIP:Bool {
|
||
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
|
||
//存在旧版购买数据,默认为VIP
|
||
return true
|
||
}else {
|
||
//获取VIP过期时间
|
||
guard let lastDate = UserDefaults.standard.object(forKey: "PurchaseVIPDate") as? Date, lastDate.timeIntervalSince(Date()) > 0 else { return false }
|
||
return true
|
||
}
|
||
}
|
||
|
||
override init() {
|
||
super.init()
|
||
|
||
}
|
||
deinit {
|
||
|
||
}
|
||
///校正内购产品交易情况
|
||
func observeVIPStoreKit() {
|
||
//清理原有的交易信息组
|
||
transactions.removeAll()
|
||
//执行交易信息组校正处理
|
||
SwiftyStoreKit.completeTransactions { [weak self] purchases in
|
||
guard let self = self else { return }
|
||
var productId = ""
|
||
//检查交易情况
|
||
print("检索交易")
|
||
purchases.forEach { item in
|
||
switch item.transaction.transactionState {
|
||
case .purchased, .restored://交易完成/处理中
|
||
//检查交易是否需要强制终结
|
||
if item.needsFinishTransaction {
|
||
SwiftyStoreKit.finishTransaction(item.transaction)
|
||
}
|
||
//更新产品ID
|
||
productId = item.productId
|
||
//添加交易信息组
|
||
self.transactions.append(item.transaction)
|
||
case .failed://交易失败
|
||
//检查交易是否需要强制终结
|
||
if item.needsFinishTransaction {
|
||
SwiftyStoreKit.finishTransaction(item.transaction)
|
||
}
|
||
default:
|
||
break
|
||
}
|
||
}
|
||
//交易检索完毕,查看是否有订阅的产品
|
||
if !productId.isEmpty {
|
||
//存在交易产品,重新验证一下流程
|
||
print("当前用户有VIP记录,进行验证")
|
||
self.showHUD = false
|
||
self.purchaseVerificationProductVIP(with: productId)
|
||
}else {
|
||
//无交易内容
|
||
print("当前用户非VIP")
|
||
}
|
||
}
|
||
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
|
||
restorePurchases(true)
|
||
}
|
||
}
|
||
///获取内购产品信息
|
||
func getVIPAllProducts() {
|
||
let productIds:Set<String> = Set(productIdentifiers)
|
||
SwiftyStoreKit.retrieveProductsInfo(productIds) { [weak self] results in
|
||
guard let self = self else { return }
|
||
//检索产品信息
|
||
if !results.retrievedProducts.isEmpty {
|
||
self.availableProducts = results.retrievedProducts
|
||
}
|
||
}
|
||
}
|
||
|
||
///对指定产品进行购买
|
||
func purchaseProduct(with productId:String) {
|
||
showHUD = true
|
||
MP_HUD.loading()
|
||
//判断当前的购买状态是否可以继续执行
|
||
if SwiftyStoreKit.canMakePayments {
|
||
//可以继续购买项目
|
||
MP_AnalyticsManager.shared.VIP_continue_clickAction(productId)
|
||
self.pruchaseProductVIP(with: productId)
|
||
}else {
|
||
//不可以购买项目
|
||
MP_HUD.error("Sorry. Subscription purchase failed", delay: 1.0, completion: nil)
|
||
MP_AnalyticsManager.shared.VIP_buy_failureAction(productId, error: "The current project status is not supported")
|
||
}
|
||
}
|
||
|
||
///用户重新检索交易
|
||
func restorePurchases(_ isLaunch:Bool = false) {
|
||
if isLaunch == true {
|
||
showHUD = false
|
||
}else {
|
||
MP_HUD.loading()
|
||
showHUD = true
|
||
}
|
||
self.transactions.removeAll()
|
||
SwiftyStoreKit.restorePurchases(atomically: false) { [weak self] results in
|
||
guard let self = self else { return }
|
||
if !results.restoredPurchases.isEmpty, let productId = results.restoredPurchases.first?.productId {
|
||
//restore成功
|
||
self.transactions.append(contentsOf: results.restoredPurchases.map({$0.transaction}))
|
||
self.purchaseVerificationProductVIP(with: productId)
|
||
return
|
||
}
|
||
if !results.restoreFailedPurchases.isEmpty {
|
||
MP_HUD.error("Restore purchase failed", delay: 1.0, completion: nil)
|
||
return
|
||
}
|
||
MP_HUD.error("No purchase can be restored", delay: 1.0, completion: nil)
|
||
}
|
||
}
|
||
|
||
|
||
|
||
}
|
||
//MARK: - 交易执行
|
||
extension MP_IAPManager {
|
||
///执行交易
|
||
private func pruchaseProductVIP(with productId:String) {
|
||
//优先移除交易信息组
|
||
self.transactions.removeAll()
|
||
SwiftyStoreKit.purchaseProduct(productId, quantity: 1, atomically: false) { [weak self] (result) in
|
||
guard let self = self else { return }
|
||
switch result {
|
||
case .success(let product)://订阅成功
|
||
print("VIP Purchase Successfully.")
|
||
//更新订阅信息
|
||
self.transactions.append(product.transaction)
|
||
//检索交易信息
|
||
self.purchaseVerificationProductVIP(with: product.productId)
|
||
case .error(let error)://订阅失败
|
||
MP_HUD.error("Sorry. Subscription purchase failed", delay: 1.0, completion: nil)
|
||
MP_AnalyticsManager.shared.VIP_buy_failureAction(productId, error: "The current project status is not supported")
|
||
print("VIP: \(error.localizedDescription)")
|
||
}
|
||
}
|
||
}
|
||
///交易验证
|
||
private func purchaseVerificationProductVIP(with productId:String) {
|
||
//生成一个验证服务器
|
||
let receiptValidator = AppleReceiptValidator(service: checkIsSandbox() ? .sandbox:.production, sharedSecret: "d29627e4f78b4b50a0ce5166acd8aa9f")
|
||
SwiftyStoreKit.verifyReceipt(using: receiptValidator, forceRefresh: true) { [weak self] result in
|
||
guard let self = self else { return }
|
||
switch result {
|
||
case .success(let receipt)://验证成功
|
||
print("VIP Receipt: \(receipt)")
|
||
//检索是否为终身项目
|
||
if productId == "lifetimevip" {
|
||
//终身项目
|
||
let purchaseResult = SwiftyStoreKit.verifyPurchase(productId: productId, inReceipt: receipt)
|
||
switch purchaseResult {
|
||
case .purchased(let item):
|
||
print("VIP LifeTime verifyPurchase successed current item: \(item)")
|
||
//到期时间一百年后
|
||
let lifeDate = Date().addingTimeInterval(60 * 60 * 24 * 365 * 100)
|
||
//本地记录VIP到期时间
|
||
UserDefaults.standard.set(lifeDate, forKey: "PurchaseVIPDate")
|
||
UserDefaults.standard.synchronize()
|
||
//结算交易信息
|
||
self.showSuccessfullyHUD()
|
||
self.finishedAllTransactionsVIP()
|
||
case .notPurchased://订阅失败
|
||
self.finishedAllTransactionsVIP()
|
||
self.showFailedHUD()
|
||
}
|
||
}else {
|
||
//非终身项目,要计算项目时间
|
||
let purchaseResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)
|
||
switch purchaseResult {
|
||
case .purchased(let expiryDate, let items):
|
||
print("VIP \(productId) valid until \(expiryDate)")
|
||
UserDefaults.standard.set(expiryDate, forKey: "PurchaseVIPDate")
|
||
UserDefaults.standard.synchronize()
|
||
//结算交易信息
|
||
self.showSuccessfullyHUD()
|
||
self.finishedAllTransactionsVIP()
|
||
case .expired(let expiryDate, let items)://过期了
|
||
self.finishedAllTransactionsVIP()
|
||
self.showFailedHUD()
|
||
case .notPurchased://订阅失败
|
||
self.finishedAllTransactionsVIP()
|
||
self.showFailedHUD()
|
||
}
|
||
}
|
||
//清理旧版信息
|
||
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
|
||
print("清理旧版VIP信息")
|
||
UserDefaults.standard.set(nil, forKey: "PurchasedProducts")
|
||
}
|
||
case .error(let error)://验证失败
|
||
self.finishedAllTransactionsVIP()
|
||
self.showFailedHUD()
|
||
}
|
||
}
|
||
}
|
||
//展示交易成功
|
||
private func showSuccessfullyHUD() {
|
||
if showHUD == true {
|
||
MP_HUD.success("Successfully purchased", delay: 1.5, completion: nil)
|
||
}
|
||
}
|
||
//展示交易失败
|
||
private func showFailedHUD() {
|
||
if showHUD == true {
|
||
MP_HUD.error("Failed purchased", delay: 1.5, completion: nil)
|
||
}
|
||
}
|
||
|
||
//结算交易信息组
|
||
private func finishedAllTransactionsVIP() {
|
||
self.transactions.forEach { item in
|
||
SwiftyStoreKit.finishTransaction(item)
|
||
}
|
||
self.transactions.removeAll()
|
||
}
|
||
|
||
private func checkIsSandbox() -> Bool {
|
||
var isSandbox = false
|
||
#if DEBUG
|
||
isSandbox = true
|
||
#endif
|
||
return isSandbox
|
||
}
|
||
}
|
||
|