|
@@ -9,25 +9,37 @@ import Foundation
|
|
|
import StoreKit
|
|
|
|
|
|
public enum PremiumPeriod: String, CaseIterable {
|
|
|
- case none = ""
|
|
|
- case week = "Week"
|
|
|
- case month = "Monthly"
|
|
|
- case year = "Yearly"
|
|
|
- case lifetime = "Lifetime"
|
|
|
+ case none = ""
|
|
|
+ case week = "Week"
|
|
|
+ case month = "Monthly"
|
|
|
+ case year = "Yearly"
|
|
|
+ case lifetime = "Lifetime"
|
|
|
+
|
|
|
+ /// 对应vip类型,可以免费使用次数
|
|
|
+ var freeNumber: Int {
|
|
|
+ switch self {
|
|
|
+ case .week:
|
|
|
+ return 30
|
|
|
+ case .year:
|
|
|
+ return 50
|
|
|
+ default:
|
|
|
+ return 30
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public enum VipFreeNumType: String, CaseIterable {
|
|
|
- case none = "kNone"
|
|
|
- case generatePic = "kGeneratePicFreeNum"
|
|
|
- case aichat = "kAIChatFreeNum"
|
|
|
- case textGeneratePic = "kTextGeneratePicFreeNum"
|
|
|
- case picToPic = "kPicToPicFreeNum"
|
|
|
+ case none = "kNone"
|
|
|
+ case generatePic = "kGeneratePicFreeNum"
|
|
|
+ case aichat = "kAIChatFreeNum"
|
|
|
+ case textGeneratePic = "kTextGeneratePicFreeNum"
|
|
|
+ case picToPic = "kPicToPicFreeNum"
|
|
|
}
|
|
|
|
|
|
public struct PurchaseProduct {
|
|
|
public let productId: String
|
|
|
public let period: PremiumPeriod
|
|
|
-
|
|
|
+
|
|
|
public init(productId: String, period: PremiumPeriod) {
|
|
|
self.productId = productId
|
|
|
self.period = period
|
|
@@ -36,50 +48,49 @@ public struct PurchaseProduct {
|
|
|
|
|
|
public enum PremiumRequestState {
|
|
|
case none
|
|
|
-
|
|
|
+
|
|
|
case loading
|
|
|
case loadSuccess
|
|
|
case loadFail
|
|
|
-
|
|
|
+
|
|
|
case paying
|
|
|
case paySuccess
|
|
|
case payFail
|
|
|
-
|
|
|
+
|
|
|
case restoreing
|
|
|
case restoreSuccess
|
|
|
case restoreFail
|
|
|
-
|
|
|
+
|
|
|
case verifying
|
|
|
case verifySuccess
|
|
|
case verifyFail
|
|
|
}
|
|
|
|
|
|
-
|
|
|
public extension Notification.Name {
|
|
|
- static let kPurchasePrepared = Self.init("kPurchaseProductPrepared")
|
|
|
- static let kPurchaseDidChanged = Self.init("kPurchaseDidChanged")
|
|
|
+ static let kPurchasePrepared = Self("kPurchaseProductPrepared")
|
|
|
+ static let kPurchaseDidChanged = Self("kPurchaseDidChanged")
|
|
|
}
|
|
|
|
|
|
private let kFreeNumKey = "kFreeNumKey"
|
|
|
+private let kTotalUseNumKey = "kTotalUseNumKey"
|
|
|
private let kPremiumExpiredInfoKey = "premiumExpiredInfoKey"
|
|
|
|
|
|
-
|
|
|
typealias PurchaseStateChangeHandler = (_ manager: PurchaseManager, _ state: PremiumRequestState, _ object: Any?) -> Void
|
|
|
|
|
|
let kPurchaseDefault = PurchaseManager.default
|
|
|
public class PurchaseManager: NSObject {
|
|
|
@objc public static let `default` = PurchaseManager()
|
|
|
|
|
|
- //苹果共享密钥
|
|
|
- private let AppleSharedKey:String = "7fa595ea66a54b16b14ca2e2bf40f276"
|
|
|
-
|
|
|
- //商品信息
|
|
|
- public lazy var purchaseProducts:[PurchaseProduct] = {
|
|
|
- return [
|
|
|
+ // 苹果共享密钥
|
|
|
+ private let AppleSharedKey: String = "7fa595ea66a54b16b14ca2e2bf40f276"
|
|
|
+
|
|
|
+ // 商品信息
|
|
|
+ public lazy var purchaseProducts: [PurchaseProduct] = {
|
|
|
+ [
|
|
|
// PurchaseProduct(productId: "101", period:.month),
|
|
|
- PurchaseProduct(productId: "102", period:.year),
|
|
|
- PurchaseProduct(productId: "103", period:.week),
|
|
|
- //PurchaseProduct(productId: "003", period: .lifetime),
|
|
|
+ PurchaseProduct(productId: "102", period: .year),
|
|
|
+ PurchaseProduct(productId: "103", period: .week),
|
|
|
+ // PurchaseProduct(productId: "003", period: .lifetime),
|
|
|
]
|
|
|
}()
|
|
|
|
|
@@ -96,11 +107,17 @@ public class PurchaseManager: NSObject {
|
|
|
var vipInformation: [String: Any] = [:]
|
|
|
|
|
|
// 免费使用会员的次数
|
|
|
- var freeDict:[String:Int] = [:]
|
|
|
-
|
|
|
- //原始订单交易id dict
|
|
|
- var originalTransactionIdentifierDict:[String:String] = [:]
|
|
|
-
|
|
|
+ var freeDict: [String: Int] = [:]
|
|
|
+
|
|
|
+ // 原始订单交易id dict
|
|
|
+ var originalTransactionIdentifierDict: [String: String] = [:]
|
|
|
+
|
|
|
+ public var totalUsedTimes: Int = 0
|
|
|
+
|
|
|
+ public var isOverTotalTimes: Bool {
|
|
|
+ return totalUsedTimes >= vipType.freeNumber
|
|
|
+ }
|
|
|
+
|
|
|
override init() {
|
|
|
super.init()
|
|
|
|
|
@@ -109,7 +126,7 @@ public class PurchaseManager: NSObject {
|
|
|
if let info = UserDefaults.standard.object(forKey: kPremiumExpiredInfoKey) as? [String: Any] {
|
|
|
vipInformation = info
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
initializeForFree()
|
|
|
}
|
|
|
|
|
@@ -121,7 +138,7 @@ public class PurchaseManager: NSObject {
|
|
|
}
|
|
|
|
|
|
public var expiredDateString: String {
|
|
|
- if vipType == .lifetime{
|
|
|
+ if vipType == .lifetime {
|
|
|
return "Life Time"
|
|
|
} else {
|
|
|
if let expDate = expiredDate {
|
|
@@ -144,9 +161,9 @@ public class PurchaseManager: NSObject {
|
|
|
}
|
|
|
|
|
|
@objc public var isVip: Bool {
|
|
|
-// #if DEBUG
|
|
|
-// return true
|
|
|
-// #endif
|
|
|
+ #if DEBUG
|
|
|
+ return true
|
|
|
+ #endif
|
|
|
guard let expiresDate = expiredDate else {
|
|
|
return false
|
|
|
}
|
|
@@ -213,44 +230,41 @@ extension PurchaseManager {
|
|
|
guard let product = product(for: period) else {
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
var originPrice = product.price
|
|
|
let price = originPrice.doubleValue
|
|
|
if period == .year {
|
|
|
originPrice = NSDecimalNumber(string: String(format: "%.2f", price / 52.0), locale: nil)
|
|
|
- }else if period == .month {
|
|
|
+ } else if period == .month {
|
|
|
originPrice = NSDecimalNumber(string: String(format: "%.2f", price / 4.0), locale: nil)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let formatter = NumberFormatter()
|
|
|
formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
|
|
|
formatter.numberStyle = .currency
|
|
|
formatter.locale = product.priceLocale
|
|
|
return formatter.string(from: originPrice)
|
|
|
-
|
|
|
}
|
|
|
-
|
|
|
|
|
|
// 平均每天的金额
|
|
|
public func averageDay(for period: PremiumPeriod) -> String? {
|
|
|
guard let product = product(for: period) else {
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
var originPrice = product.price
|
|
|
let price = originPrice.doubleValue
|
|
|
if period == .year {
|
|
|
originPrice = NSDecimalNumber(string: String(format: "%.2f", price / 365.0), locale: nil)
|
|
|
- }else if period == .month {
|
|
|
+ } else if period == .month {
|
|
|
originPrice = NSDecimalNumber(string: String(format: "%.2f", price / 30.0), locale: nil)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let formatter = NumberFormatter()
|
|
|
formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
|
|
|
formatter.numberStyle = .currency
|
|
|
formatter.locale = product.priceLocale
|
|
|
return formatter.string(from: originPrice)
|
|
|
-
|
|
|
}
|
|
|
// public func originalPrice(for period: PremiumPeriod) -> String? {
|
|
|
// guard let product = product(for: period) else {
|
|
@@ -278,7 +292,7 @@ extension PurchaseManager {
|
|
|
// MARK: 商品 & 订阅请求
|
|
|
|
|
|
extension PurchaseManager {
|
|
|
- ///请求商品
|
|
|
+ /// 请求商品
|
|
|
public func requestProducts() {
|
|
|
if !products.isEmpty {
|
|
|
purchase(self, didChaged: .loadSuccess, object: nil)
|
|
@@ -296,7 +310,7 @@ extension PurchaseManager {
|
|
|
purchase(self, didChaged: .restoreing, object: nil)
|
|
|
SKPaymentQueue.default().restoreCompletedTransactions()
|
|
|
debugPrint("PurchaseManager restoreCompletedTransactions")
|
|
|
-
|
|
|
+
|
|
|
subscriptionApple(type: .created, jsonString: "Payment restore")
|
|
|
}
|
|
|
|
|
@@ -317,9 +331,9 @@ extension PurchaseManager {
|
|
|
let payment = SKPayment(product: product)
|
|
|
SKPaymentQueue.default().add(payment)
|
|
|
debugPrint("PurchaseManager pay period = \(period)")
|
|
|
-
|
|
|
+
|
|
|
subscriptionApple(type: .created, jsonString: "Payment period = \(product)")
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
purchase(self, didChaged: .payFail, object: "Payment failed, no this item")
|
|
|
}
|
|
|
}
|
|
@@ -348,15 +362,14 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
|
|
debugPrint("PurchaseManager paymentQueue transactions.count = \(transactions.count)")
|
|
|
// debugPrint("PurchaseManager paymentQueue transactions = \(transactions)")
|
|
|
-
|
|
|
+
|
|
|
originalTransactionIdentifierDict.removeAll()
|
|
|
// 因为只有订阅类的购买项
|
|
|
for transaction in transactions {
|
|
|
-
|
|
|
// debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier original= \(transaction.original?.transactionIdentifier)")
|
|
|
// debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier = \(transaction.transactionIdentifier)")
|
|
|
// debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier productIdentifier = \(transaction.payment.productIdentifier)")
|
|
|
-
|
|
|
+
|
|
|
switch transaction.transactionState {
|
|
|
case .purchasing:
|
|
|
// Transaction is being added to the server queue.
|
|
@@ -364,21 +377,20 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
|
|
|
case .purchased:
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
|
- //同样的原始订单,只处理一次.
|
|
|
+ // 同样的原始订单,只处理一次.
|
|
|
guard judgeWhether(transaction: transaction) else {
|
|
|
break
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Transaction is in queue, user has been charged. Client should complete the transaction.
|
|
|
#if DEBUG
|
|
|
verifyPayResult(transaction: transaction, useSandBox: true)
|
|
|
#else
|
|
|
verifyPayResult(transaction: transaction, useSandBox: false)
|
|
|
#endif
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
case .failed:
|
|
|
-
|
|
|
+
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
|
// Transaction was cancelled or failed before being added to the server queue.
|
|
|
var message = "Payment Failed"
|
|
@@ -390,11 +402,11 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
subscriptionApple(type: .result, jsonString: message)
|
|
|
case .restored:
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
|
- //同样的原始订单,只处理一次.
|
|
|
+ // 同样的原始订单,只处理一次.
|
|
|
guard judgeWhether(transaction: transaction) else {
|
|
|
break
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Transaction was restored from user's purchase history. Client should complete the transaction.
|
|
|
if let original = transaction.original,
|
|
|
original.transactionState == .purchased {
|
|
@@ -407,7 +419,7 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
purchase(self, didChaged: .restoreFail, object: "Failed to restore subscribe, please try again")
|
|
|
subscriptionApple(type: .result, jsonString: "Failed to restore subscribe, please try again")
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
case .deferred: // The transaction is in the queue, but its final status is pending external action.
|
|
|
break
|
|
|
@unknown default:
|
|
@@ -427,8 +439,8 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
purchase(self, didChaged: .restoreFail, object: "You don't have an active subscription")
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- func judgeWhether(transaction:SKPaymentTransaction) -> Bool {
|
|
|
+
|
|
|
+ func judgeWhether(transaction: SKPaymentTransaction) -> Bool {
|
|
|
let id = transaction.original?.transactionIdentifier
|
|
|
if let id = id {
|
|
|
if let value = originalTransactionIdentifierDict[id] {
|
|
@@ -460,8 +472,8 @@ extension PurchaseManager {
|
|
|
}
|
|
|
|
|
|
let verifyUrlString = useSandBox ? Config.sandBoxUrl : Config.verifyUrl
|
|
|
-
|
|
|
- postRequest(urlString: verifyUrlString, httpBody: requestData) { [weak self] data, error in
|
|
|
+
|
|
|
+ postRequest(urlString: verifyUrlString, httpBody: requestData) { [weak self] data, _ in
|
|
|
guard let self = self else { return }
|
|
|
if let data = data,
|
|
|
let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
@@ -483,17 +495,17 @@ extension PurchaseManager {
|
|
|
debugPrint("PurchaseManager 验证结果为空")
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/*
|
|
|
- 21000 App Store无法读取你提供的JSON数据
|
|
|
- 21002 收据数据不符合格式
|
|
|
- 21003 收据无法被验证
|
|
|
- 21004 你提供的共享密钥和账户的共享密钥不一致
|
|
|
- 21005 收据服务器当前不可用
|
|
|
- 21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
|
|
|
- 21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
|
|
|
- 21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
|
|
|
- */
|
|
|
+ 21000 App Store无法读取你提供的JSON数据
|
|
|
+ 21002 收据数据不符合格式
|
|
|
+ 21003 收据无法被验证
|
|
|
+ 21004 你提供的共享密钥和账户的共享密钥不一致
|
|
|
+ 21005 收据服务器当前不可用
|
|
|
+ 21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
|
|
|
+ 21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
|
|
|
+ 21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
|
|
|
+ */
|
|
|
}
|
|
|
|
|
|
func handlerPayResult(transaction: SKPaymentTransaction, resp: [String: Any]) {
|
|
@@ -533,17 +545,16 @@ extension PurchaseManager {
|
|
|
self.purchase(self, didChaged: .paySuccess, object: nil)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
subscriptionApple(type: .result, jsonString: simplifyVerifyPayResult(resp: resp))
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 终生会员过期时间:100年
|
|
|
var lifetimeExpireTime: String {
|
|
|
let date = Date().addingTimeInterval(100 * 365 * 24 * 60 * 60)
|
|
|
return "\(date.timeIntervalSince1970 * 1000)"
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/// 发送 POST 请求
|
|
|
/// - Parameters:
|
|
|
/// - urlString: 请求的 URL 字符串
|
|
@@ -561,7 +572,7 @@ extension PurchaseManager {
|
|
|
completion(nil, NSError(domain: "Invalid URL", code: -1, userInfo: nil))
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
dePrint("postRequest urlString=\(urlString)")
|
|
|
// 创建请求
|
|
|
var request = URLRequest(url: url)
|
|
@@ -569,12 +580,12 @@ extension PurchaseManager {
|
|
|
request.timeoutInterval = timeout
|
|
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
|
request.httpBody = httpBody
|
|
|
-
|
|
|
+
|
|
|
// 创建数据任务
|
|
|
- let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
|
+ let task = URLSession.shared.dataTask(with: request) { data, _, error in
|
|
|
completion(data, error)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 启动任务
|
|
|
task.resume()
|
|
|
}
|
|
@@ -587,75 +598,100 @@ public extension PurchaseManager {
|
|
|
}
|
|
|
return isVip
|
|
|
}
|
|
|
-
|
|
|
- func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?){
|
|
|
- onPurchaseStateChanged?(manager,state,object)
|
|
|
+
|
|
|
+ func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?) {
|
|
|
+ onPurchaseStateChanged?(manager, state, object)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/// 免费生成图片次数
|
|
|
extension PurchaseManager {
|
|
|
/// 使用一次免费次数
|
|
|
- func useOnceForFree(type:VipFreeNumType){
|
|
|
-
|
|
|
+ func useOnceForFree(type: VipFreeNumType) {
|
|
|
+ /// 总使用次数
|
|
|
+ saveForTotalUse()
|
|
|
+ print("🙅🙅🙅🙅🙅🙅🙅🙅🙅🙅🙅")
|
|
|
if isVip {
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
var freeNum = freeDict[type.rawValue] ?? 0
|
|
|
if freeNum > 0 {
|
|
|
- freeNum-=1
|
|
|
+ freeNum -= 1
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if freeNum < 0 {
|
|
|
freeNum = 0
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
freeDict[type.rawValue] = freeNum
|
|
|
saveForFree()
|
|
|
-
|
|
|
+
|
|
|
NotificationCenter.default.post(name: .kVipFreeNumChanged, object: nil, userInfo: ["VipFreeNumType": type])
|
|
|
}
|
|
|
-
|
|
|
- func freeNum(type:VipFreeNumType) -> Int{
|
|
|
+
|
|
|
+ func freeNum(type: VipFreeNumType) -> Int {
|
|
|
let freeNum = freeDict[type.rawValue] ?? 0
|
|
|
return freeNum
|
|
|
}
|
|
|
-
|
|
|
- func saveForFree(){
|
|
|
+
|
|
|
+ func saveForFree() {
|
|
|
UserDefaults.standard.set(freeDict, forKey: kFreeNumKey)
|
|
|
UserDefaults.standard.synchronize()
|
|
|
}
|
|
|
-
|
|
|
- func initializeForFree(){
|
|
|
- if let dict = UserDefaults.standard.dictionary(forKey: kFreeNumKey) as? [String:Int]{
|
|
|
+
|
|
|
+ func saveForTotalUse() {
|
|
|
+ // 先加载当前记录(确保日期正确)
|
|
|
+ loadTotalUse()
|
|
|
+
|
|
|
+ // 增加使用次数
|
|
|
+ totalUsedTimes += 1
|
|
|
+
|
|
|
+ // 保存新的记录
|
|
|
+ let dict: [String: Any] = ["date": Date().dateDayString, "times": totalUsedTimes]
|
|
|
+ UserDefaults.standard.set(dict, forKey: kTotalUseNumKey)
|
|
|
+ UserDefaults.standard.synchronize()
|
|
|
+ }
|
|
|
+
|
|
|
+ func loadTotalUse() {
|
|
|
+ // 当天没记录,设置默认次数
|
|
|
+ guard let dict = UserDefaults.standard.dictionary(forKey: kTotalUseNumKey),
|
|
|
+ dict.safeString(forKey: "date") == Date().dateDayString else {
|
|
|
+ totalUsedTimes = 0
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 有记录,设置已经使用次数
|
|
|
+ totalUsedTimes = dict.safeInt(forKey: "times")
|
|
|
+ }
|
|
|
+
|
|
|
+ func initializeForFree() {
|
|
|
+ if let dict = UserDefaults.standard.dictionary(forKey: kFreeNumKey) as? [String: Int] {
|
|
|
freeDict = dict
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
freeDict = [
|
|
|
- VipFreeNumType.generatePic.rawValue:1,
|
|
|
- VipFreeNumType.aichat.rawValue:1,
|
|
|
- VipFreeNumType.textGeneratePic.rawValue:1,
|
|
|
- VipFreeNumType.picToPic.rawValue:1
|
|
|
+ VipFreeNumType.generatePic.rawValue: 1,
|
|
|
+ VipFreeNumType.aichat.rawValue: 1,
|
|
|
+ VipFreeNumType.textGeneratePic.rawValue: 1,
|
|
|
+ VipFreeNumType.picToPic.rawValue: 1,
|
|
|
]
|
|
|
saveForFree()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/// 免费次数是否可用
|
|
|
- func freeNumAvailable(type:VipFreeNumType) -> Bool{
|
|
|
+ func freeNumAvailable(type: VipFreeNumType) -> Bool {
|
|
|
if isVip == true {
|
|
|
return true
|
|
|
- }else{
|
|
|
- if let freeNum = freeDict[type.rawValue],freeNum > 0 {
|
|
|
+ } else {
|
|
|
+ if let freeNum = freeDict[type.rawValue], freeNum > 0 {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/// 是否展示生成类的会员图标
|
|
|
- func generateVipShow(type:VipFreeNumType) -> Bool{
|
|
|
+ func generateVipShow(type: VipFreeNumType) -> Bool {
|
|
|
if isVip == false, freeNum(type: type) > 0 {
|
|
|
return false
|
|
|
}
|
|
@@ -663,13 +699,12 @@ extension PurchaseManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
-
|
|
|
+
|
|
|
首先,创建SKProductsRequest对象并使用init(productIdentifiers:)初始化,传入要查询的产品标识符。
|
|
|
然后,调用start()方法开始请求产品信息。
|
|
|
当请求成功时,productsRequest(_:didReceive:)方法会被调用,在这里可以获取产品详细信息并展示给用户(如在界面上显示产品价格、名称等)。如果请求失败,productsRequest(_:didFailWithError:)方法会被调用来处理错误。
|
|
|
当用户决定购买某个产品后,根据产品信息(SKProduct对象)创建SKPayment对象,然后使用SKPaymentQueue的add(_:)方法将支付请求添加到支付队列。
|
|
|
同时,在应用启动等合适的时机,通过SKPaymentQueue的addTransactionObserver(_:)方法添加交易观察者。当支付状态发生变化时,paymentQueue(_:updatedTransactions:)方法会被调用,在这里可以根据交易状态(如购买成功、失败、恢复等)进行相应的处理。
|
|
|
-
|
|
|
+
|
|
|
*/
|