【问题标题】:Auto-Renewing with SwiftyStoreKit使用 SwiftyStoreKit 自动更新
【发布时间】:2021-07-01 06:47:45
【问题描述】:

SwiftyStoreKit 对我来说是一个非常困难的产品,因为将近一周,我在 StackOverflow、YouTube 和 Google 中到处搜索答案。由于我正在研究 Auto-Renewable,因此我找不到任何答案,并且我试图找出用户是否取消订阅或过期,应用程序会要求重新订阅。在测试期间,购买效果很好,但我需要弄清楚应用程序如何知道订阅是否过期。每次我尝试验证时,我的验证收据总是会返回以下错误消息。我做错了什么?

Receipt verification failed: receiptInvalid(receipt: ["status": 21002], status: SwiftyStoreKit.ReceiptStatus.malformedOrMissingData)

这是我的顶级代码:

import SwiftyStoreKit

var sharedSecret = " * My shared Secret * "
let appleValidator = AppleReceiptValidator(service: .sandbox, sharedSecret: sharedSecret)

enum RegisteredPurchase: String {
    case autoRenewable = " * My Auto-Renewable Bundle ID * "
}

购买时带有按钮的代码

@objc func startSub() {
   StoreManager.shared.purchase(purchase: RegisteredPurchase.autoRenewable)
}

AppDelegate.swift

SwiftyStoreKit.completeTransactions(atomically: true) { purchaseStatus in
   for products in purchaseStatus {
      switch products.transaction.transactionState {
      case .purchased,.restored:
         if products.needsFinishTransaction {
            SwiftyStoreKit.finishTransaction(products.transaction)
         }
      default: break
      }
   }
}

SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
   switch result {
   case .success(let receipt):
      let productID = Set([RegisteredPurchase.autoRenewable.rawValue])
      let purchaseResult = SwiftyStoreKit.verifySubscriptions(productIds: productID, inReceipt: receipt)
      switch purchaseResult {
      case .purchased(let expiryDate, let items):
         print("\(productID) are valid until \(expiryDate), \(items).")
      case .expired(let expiryDate, let items):
         print("\(productID) are expired since \(expiryDate), \(items).")
      case .notPurchased:
         print("The product has never purchased...")
      }
   case .error(let error):
      print("Receipt verification failed: \(error)")
   }
}

StoreKitManager.swift

class StoreManager: NSObject {
   @objc static let shared = StoreManager()

   func getInfo(purchase: RegisteredPurchase) {
      SwiftyStoreKit.retrieveProductsInfo([purchase.rawValue], completion: { result in
         if result.error == nil {
            for x in result.retrievedProducts {
               print("Get Information: \(x.localizedTitle)")
            }
         } else {
             print("Error getting information")
         }
      })
   }

   func purchase(purchase: RegisteredPurchase) {
      SwiftyStoreKit.purchaseProduct(purchase.rawValue, completion: { result in
          if case .success(let product) = result {
              if product.needsFinishTransaction {
                  SwiftyStoreKit.finishTransaction(product.transaction)
              }
              print("Purchasing: \(result)")
              self.purchaseResult(result: result)
          }
      })
   }

    
   func verifyReceipt() {
       SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: { result in
           self.verifyReceipt(result: result)
           if case .error(let error) = result {
               if case .noReceiptData = error {
                   self.refreshReceipt()
               }
           }
       })
   }
    
   func verifyPurchase(product: RegisteredPurchase) {
       SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: { result in
           switch result {
           case .success(let receipt):
               let productID = RegisteredPurchase.autoRenewable
               if product == .autoRenewable {
                   let purchseResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productID.rawValue, inReceipt: receipt, validUntil: Date())
                   print("Verify Purchase Result: \(purchseResult)")
               }
           case .error(let error):
               print("Error verify purchase: \(error)")
               if case .noReceiptData = error {
                   self.refreshReceipt()
               }
           }
       })
   }
   
   func refreshReceipt() {
       SwiftyStoreKit.fetchReceipt(forceRefresh: true, completion: { result in
           print("Start refreshing the receipt...")
       })
   }
   
   func purchaseResult(result: PurchaseResult) {
       switch result {
       case .success(let product):
           print("Purchase Successful: \(product.productId)")
       case .error(let error):
           print("Purchase Failed: \(error)")
       }
   }
   
   func restoreResult(result: RestoreResults) {
       if result.restoreFailedPurchases.count > 0 {
           print("Restore failed by unknown error")
       } else if result.restoredPurchases.count > 0 {
           print("Restore Successful")
       } else {
           print("Nothing to Restore.")
       }
   }
   
   func verifyReceipt(result: VerifyReceiptResult) {
       switch result {
       case .success(let receipt): return print("Verify Receipt: \(receipt)")
       case .error(let error):
           switch error {
           case .noRemoteData: return print("No receipt founded. Try again")
           default: return print("Error Verify Receipt: \(error)")
           }
       }
   }
   
   func verifySubscription(result: VerifySubscriptionResult) {
       switch result {
       case .purchased(let expiryDate):
           print("Product is purchased, valid until \(expiryDate)")
       case .notPurchased:
           print("Product has never purchased.")
       case .expired(let expiredDate):
           print("The product is expired since \(expiredDate)!")
       }
   }
   
   func verifyPurchase(result: VerifyPurchaseResult) {
       switch result {
       case .purchased: print("Product is purchased, will not expired.")
       case .notPurchased: print("Product is not purchased, has never been purchased.")
       }
   }
   
   func refreshReceipt(result: FetchReceiptResult) {
      switch result {
      case .success(let receiptData): print("Receipt Refreshed, \(receiptData)")
      case .error(let receiptData): print("Receipt not Refresh, \(receiptData)")
      }
   }
}

【问题讨论】:

  • 您找到解决方案了吗?

标签: ios swift storekit receipt-validation swiftystorekit


【解决方案1】:

我是 StoreKit 的新手,但这是我的 2 美分。错误消息表明您的服务器可能存在问题,无法接收有效数据。

这是 Apple 所说的。

不要从您的应用调用 App Store 服务器 verifyReceipt 端点。您无法直接在用户设备和 App Store 之间建立受信任的连接,因为您无法控制该连接的任何一端,这使其容易受到中间机攻击。

Validating Receipts with the App Store

【讨论】:

  • 谢谢!但总的来说,如果我不是特别担心有人伪造订阅,我可以拨打客户的验证电话,对吗?我的意思是,Apple 提供了 API 来做到这一点。那么,如果我想在本地查看订阅状态,但遇到了这个问题,我该如何让它工作呢?
猜你喜欢
  • 1970-01-01
  • 2020-07-19
  • 2014-12-01
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多