|
@@ -17,13 +17,13 @@ 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"
|
|
|
+ let AppleSharedKey: String = "7fa595ea66a54b16b14ca2e2bf40f276"
|
|
|
|
|
|
// 商品信息
|
|
|
public lazy var purchaseProducts: [PurchaseProduct] = {
|
|
@@ -32,25 +32,16 @@ public class PurchaseManager: NSObject {
|
|
|
PurchaseProduct(productId: "102", period: .year),
|
|
|
PurchaseProduct(productId: "103", period: .week(.week)),
|
|
|
PurchaseProduct(productId: "113", period: .week(.weekPromotional1)),
|
|
|
-
|
|
|
- PurchaseProduct(productId: "201", period: .purchase(.videoNum1)),
|
|
|
- PurchaseProduct(productId: "202", period: .purchase(.videoNum2)),
|
|
|
- PurchaseProduct(productId: "203", period: .purchase(.videoNum3)),
|
|
|
]
|
|
|
}()
|
|
|
|
|
|
-
|
|
|
- lazy var purchaseNumProducts: [String] = {
|
|
|
- return ["201","202","203"]
|
|
|
- }()
|
|
|
-
|
|
|
struct Config {
|
|
|
static let verifyUrl = "https://buy.itunes.apple.com/verifyReceipt"
|
|
|
static let sandBoxUrl = "https://sandbox.itunes.apple.com/verifyReceipt"
|
|
|
}
|
|
|
|
|
|
lazy var products: [SKProduct] = []
|
|
|
-
|
|
|
+ var paymentProductIdentifier:String?
|
|
|
var onPurchaseStateChanged: PurchaseStateChangeHandler?
|
|
|
|
|
|
// 会员信息
|
|
@@ -285,10 +276,10 @@ extension PurchaseManager {
|
|
|
/// 请求商品
|
|
|
public func requestProducts() {
|
|
|
if !products.isEmpty {
|
|
|
- purchase(self, didChaged: .loadSuccess, object: nil)
|
|
|
+ purchase(self, didChaged: .loadSuccess, object: nil,transaction: nil)
|
|
|
}
|
|
|
|
|
|
- purchase(self, didChaged: .loading, object: nil)
|
|
|
+ purchase(self, didChaged: .loading, object: nil,transaction: nil)
|
|
|
let productIdentifiers = Set(purchaseProducts.map({ $0.productId }))
|
|
|
debugPrint("PurchaseManager requestProducts = \(productIdentifiers)")
|
|
|
let request = SKProductsRequest(productIdentifiers: productIdentifiers)
|
|
@@ -297,8 +288,9 @@ extension PurchaseManager {
|
|
|
}
|
|
|
|
|
|
public func restorePremium() {
|
|
|
- purchase(self, didChaged: .restoreing, object: nil)
|
|
|
+ purchase(self, didChaged: .restoreing, object: nil,transaction: nil)
|
|
|
SKPaymentQueue.default().restoreCompletedTransactions()
|
|
|
+ paymentProductIdentifier = "restoreCompletedTransactions"
|
|
|
debugPrint("PurchaseManager restoreCompletedTransactions restorePremium")
|
|
|
|
|
|
subscriptionApple(type: .created, jsonString: "Payment restore")
|
|
@@ -307,37 +299,37 @@ extension PurchaseManager {
|
|
|
/// 购买支付
|
|
|
public func pay(for period: PremiumPeriod) {
|
|
|
guard SKPaymentQueue.canMakePayments() else {
|
|
|
- purchase(self, didChaged: .payFail, object: "Payment failed, please check your payment account")
|
|
|
+ purchase(self, didChaged: .payFail, object: "Payment failed, please check your payment account",transaction: nil)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
guard SKPaymentQueue.default().transactions.count <= 0 else {
|
|
|
- purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.")
|
|
|
+ purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.",transaction: nil)
|
|
|
debugPrint("PurchaseManager pay period restorePremium = \(period)")
|
|
|
restorePremium()
|
|
|
return
|
|
|
}
|
|
|
if let product = product(for: period) {
|
|
|
- purchase(self, didChaged: .paying, object: nil)
|
|
|
+ purchase(self, didChaged: .paying, object: nil,transaction: nil)
|
|
|
let payment = SKPayment(product: product)
|
|
|
debugPrint("PurchaseManager pay product = \(product.localizedDescription)")
|
|
|
SKPaymentQueue.default().add(payment)
|
|
|
+ paymentProductIdentifier = payment.productIdentifier
|
|
|
debugPrint("PurchaseManager pay period = \(period)")
|
|
|
|
|
|
subscriptionApple(type: .created, jsonString: "Payment period = \(product)")
|
|
|
} else {
|
|
|
- purchase(self, didChaged: .payFail, object: "Payment failed, no this item")
|
|
|
+ purchase(self, didChaged: .payFail, object: "Payment failed, no this item",transaction: nil)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: 商品回调
|
|
|
-
|
|
|
extension PurchaseManager: SKProductsRequestDelegate {
|
|
|
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
|
|
let products = response.products
|
|
|
self.products = products
|
|
|
- purchase(self, didChaged: .loadSuccess, object: nil)
|
|
|
+ purchase(self, didChaged: .loadSuccess, object: nil,transaction: nil)
|
|
|
NotificationCenter.default.post(name: .kPurchasePrepared, object: nil)
|
|
|
debugPrint("PurchaseManager productsRequest didReceive = \(products)")
|
|
|
|
|
@@ -360,7 +352,7 @@ extension PurchaseManager: SKProductsRequestDelegate {
|
|
|
|
|
|
public func request(_ request: SKRequest, didFailWithError error: Error) {
|
|
|
debugPrint("PurchaseManager productsRequest error = \(error)")
|
|
|
- purchase(self, didChaged: .loadFail, object: error.localizedDescription)
|
|
|
+ purchase(self, didChaged: .loadFail, object: error.localizedDescription,transaction: nil)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -381,7 +373,7 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
switch transaction.transactionState {
|
|
|
case .purchasing:
|
|
|
// Transaction is being added to the server queue.
|
|
|
- purchase(self, didChaged: .paying, object: nil)
|
|
|
+ purchase(self, didChaged: .paying, object: nil,transaction: transaction)
|
|
|
|
|
|
case .purchased:
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
@@ -400,14 +392,14 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
case .failed:
|
|
|
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
|
-
|
|
|
+
|
|
|
//非购买次数类(就是订阅续费类)报错处理
|
|
|
- if self.purchaseNumProducts.contains(transaction.payment.productIdentifier) == false,
|
|
|
+ if TSPurchaseTimesManager.purchaseNumProducts.contains(transaction.payment.productIdentifier) == false,
|
|
|
let error = transaction.error as NSError? {
|
|
|
// 1. 检查内层错误
|
|
|
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
|
|
if underlyingError.domain == "ASDServerErrorDomain" && underlyingError.code == 3532 {
|
|
|
- print("用户已订阅,禁止重复购买")
|
|
|
+ dePrint("用户已订阅,禁止重复购买")
|
|
|
restorePremium()
|
|
|
return
|
|
|
}
|
|
@@ -416,19 +408,13 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
else if error.domain == SKErrorDomain {
|
|
|
switch SKError.Code(rawValue: error.code) {
|
|
|
case .unknown:
|
|
|
- print("未知错误,可能是服务器问题")
|
|
|
+ dePrint("未知错误,可能是服务器问题")
|
|
|
default:
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // Transaction was cancelled or failed before being added to the server queue.
|
|
|
-// var message = "Payment Failed"
|
|
|
-// if let error = transaction.error as? SKError,
|
|
|
-// error.code == SKError.paymentCancelled {
|
|
|
-// message = "The subscription was canceled"
|
|
|
-// }
|
|
|
+
|
|
|
|
|
|
var message = "Payment Failed"
|
|
|
if let error = transaction.error as? SKError{
|
|
@@ -437,10 +423,12 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
}else{
|
|
|
message = error.localizedDescription
|
|
|
}
|
|
|
+ //error.errorCode == 3532 //用户已订阅,禁止重复购买
|
|
|
}
|
|
|
|
|
|
- purchase(self, didChaged: .payFail, object: message)
|
|
|
+ purchase(self, didChaged: .payFail, object: message,transaction: transaction)
|
|
|
subscriptionApple(type: .result, jsonString: message)
|
|
|
+
|
|
|
case .restored:
|
|
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
|
// 同样的原始订单,只处理一次.
|
|
@@ -457,7 +445,7 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
verifyPayResult(transaction: transaction, useSandBox: false)
|
|
|
#endif
|
|
|
} else {
|
|
|
- purchase(self, didChaged: .restoreFail, object: "Failed to restore subscribe, please try again")
|
|
|
+ purchase(self, didChaged: .restoreFail, object: "Failed to restore subscribe, please try again",transaction: transaction)
|
|
|
subscriptionApple(type: .result, jsonString: "Failed to restore subscribe, please try again")
|
|
|
}
|
|
|
|
|
@@ -470,14 +458,14 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
}
|
|
|
|
|
|
public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
|
|
|
- purchase(self, didChaged: .restoreFail, object: nil)
|
|
|
+ purchase(self, didChaged: .restoreFail, object: nil,transaction: nil)
|
|
|
}
|
|
|
|
|
|
public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
|
|
|
if let trans = queue.transactions.first(where: { $0.transactionState == .purchased }) {
|
|
|
verifyPayResult(transaction: trans, useSandBox: false)
|
|
|
} else if queue.transactions.isEmpty {
|
|
|
- purchase(self, didChaged: .restoreFail, object: "You don't have an active subscription")
|
|
|
+ purchase(self, didChaged: .restoreFail, object: "You don't have an active subscription",transaction: nil)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -495,11 +483,11 @@ extension PurchaseManager: SKPaymentTransactionObserver {
|
|
|
|
|
|
extension PurchaseManager {
|
|
|
func verifyPayResult(transaction: SKPaymentTransaction, useSandBox: Bool) {
|
|
|
- purchase(self, didChaged: .verifying, object: nil)
|
|
|
+ purchase(self, didChaged: .verifying, object: nil,transaction: transaction)
|
|
|
|
|
|
guard let url = Bundle.main.appStoreReceiptURL,
|
|
|
let receiptData = try? Data(contentsOf: url) else {
|
|
|
- purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
|
|
|
+ purchase(self, didChaged: .verifyFail, object: "凭证文件为空",transaction: transaction)
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -508,7 +496,7 @@ extension PurchaseManager {
|
|
|
"password": AppleSharedKey,
|
|
|
]
|
|
|
guard let requestData = try? JSONSerialization.data(withJSONObject: requestContents) else {
|
|
|
- purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
|
|
|
+ purchase(self, didChaged: .verifyFail, object: "凭证文件为空",transaction: transaction)
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -529,10 +517,10 @@ extension PurchaseManager {
|
|
|
} else if let status = status as? Int, status == 0 {
|
|
|
self.handlerPayResult(transaction: transaction, resp: jsonResponse)
|
|
|
} else {
|
|
|
- self.purchase(self, didChaged: .verifyFail, object: "验证结果状态码错误:\(status.debugDescription)")
|
|
|
+ self.purchase(self, didChaged: .verifyFail, object: "验证结果状态码错误:\(status.debugDescription)",transaction: transaction)
|
|
|
}
|
|
|
} else {
|
|
|
- self.purchase(self, didChaged: .verifyFail, object: "验证结果为空")
|
|
|
+ self.purchase(self, didChaged: .verifyFail, object: "验证结果为空",transaction: transaction)
|
|
|
debugPrint("PurchaseManager 验证结果为空")
|
|
|
}
|
|
|
}
|
|
@@ -591,9 +579,9 @@ extension PurchaseManager {
|
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
if transaction.transactionState == .restored {
|
|
|
- self.purchase(self, didChaged: .restoreSuccess, object: nil)
|
|
|
+ self.purchase(self, didChaged: .restoreSuccess, object: nil,transaction: transaction)
|
|
|
} else {
|
|
|
- self.purchase(self, didChaged: .paySuccess, object: nil)
|
|
|
+ self.purchase(self, didChaged: .paySuccess, object: nil,transaction: transaction)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -606,8 +594,8 @@ extension PurchaseManager {
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
- //取当前已生效的订单号
|
|
|
- guard let info = resp["latest_receipt_info"] as? [[String: Any]]
|
|
|
+
|
|
|
+ guard let pendingRenewalInfoArray = resp["pending_renewal_info"] as? [[String: Any]]
|
|
|
else { return false}
|
|
|
|
|
|
/*
|
|
@@ -618,7 +606,7 @@ extension PurchaseManager {
|
|
|
"product_id" = 101;
|
|
|
}*/
|
|
|
|
|
|
- if let firstItem = info.first,
|
|
|
+ if let firstItem = pendingRenewalInfoArray.first ,
|
|
|
let auto_renew_product_id = firstItem["auto_renew_product_id"] as? String,
|
|
|
let auto_product_id = firstItem["product_id"] as? String {
|
|
|
if auto_renew_product_id != auto_product_id {//拿到待生效的和当前的对比不一样,以待生效的为主
|
|
@@ -626,8 +614,11 @@ extension PurchaseManager {
|
|
|
let info = resp["latest_receipt_info"] as? [[String: Any]]
|
|
|
if let firstItem = info?.first,
|
|
|
let expires_date_ms = firstItem["expires_date_ms"] as? String {
|
|
|
- let expiresms = Int(expires_date_ms) ?? 0 + period(for: auto_renew_product_id).milliseconds
|
|
|
- updateExpireTime(String(expiresms), for: auto_renew_product_id)
|
|
|
+ let expiresms = Int(expires_date_ms) ?? 0
|
|
|
+ let milliseconds = period(for: auto_renew_product_id).milliseconds
|
|
|
+ let totalExpiresms = expiresms + milliseconds
|
|
|
+
|
|
|
+ updateExpireTime(String(totalExpiresms), for: auto_renew_product_id)
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
@@ -687,8 +678,16 @@ public extension PurchaseManager {
|
|
|
return isVip
|
|
|
}
|
|
|
|
|
|
- func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?) {
|
|
|
+ func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?,transaction:SKPaymentTransaction?) {
|
|
|
onPurchaseStateChanged?(manager, state, object)
|
|
|
+
|
|
|
+ if transaction == nil{
|
|
|
+ onPurchaseStateChanged?(manager, state, object)
|
|
|
+ }else if transaction?.transactionState == .restored,paymentProductIdentifier == "restoreCompletedTransactions"{
|
|
|
+ onPurchaseStateChanged?(manager, state, object)
|
|
|
+ }else if let productIdentifier = transaction?.payment.productIdentifier, productIdentifier == paymentProductIdentifier {
|
|
|
+ onPurchaseStateChanged?(manager, state, object)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|