2

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)")
      }
   }
}

4

1 回答 1

1

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

这是苹果公司所说的。

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

使用 App Store 验证收据

于 2021-09-10T09:15:53.300 回答