ios - Swift 中 SKProduct() 的应用内购买问题

标签 ios in-app-purchase storekit

我正在尝试在我正在创建的应用程序中实现应用内购买,但是当我尝试“获取”产品时,我有 var products = [SKProducts]() 但这会返回一个空数组导致应用程序崩溃。 我已经检查了所有税务协议(protocol)等,当我在应用程序购买示例项目中的苹果中进行测试时,IAP 就会出现。

出现问题的完整代码如下。

class Model {

        var products = [SKProduct]()

        func getProduct(containing keyword: String) -> SKProduct? {
            // print("The array of SKProducts in Model getProduct is \(products)")
            // let test = products.filter { $0.productIdentifier.contains(keyword) }.first
            print("The products are: \(products)")
            print(products.filter { $0.productIdentifier.contains(keyword) }.first)
            return products.filter { $0.productIdentifier.contains(keyword) }.first
        }
    }

打印语句返回: “产品是:[]”和 “无”

如果有帮助,可以在 GitHub 上找到完整的项目 here

最佳答案

函数getProduct除了打印一个空数组(products),并过滤这个空数组并检索第一个元素(不存在)之外什么也不做。 .
我建议使用这样的助手(我从某处复制它,不记得在哪里):

import Foundation
import StoreKit

class IAPHelper: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {

  typealias RequestProductsCompletionHandler = (_ success:Bool, _ products:[SKProduct]?) -> ()
  var completionHandler: RequestProductsCompletionHandler?
  var productsRequest: SKProductsRequest?
  var productIdentifiers: Set<String>
  var purchasedProductIdentifiers: Set<String>?

  // MARK: - Init  

  init(identifiers: Set<String>) {

    // Store product identifiers
    productIdentifiers = identifiers;

    // Check for previously purchased products
    purchasedProductIdentifiers = Set()
    for productIdentifier in productIdentifiers {
      let productPurchased = UserDefaults.standard.bool(forKey: productIdentifier)
      if productPurchased {
        purchasedProductIdentifiers?.insert(productIdentifier)
                print("Previously purchased: \(productIdentifier)");
      } else {
                print("Not purchased: \(productIdentifier)");
      }
    }
    super.init() // must be called after subclass init, but before "self" is used
    SKPaymentQueue.default().add(self)
  } // init

  func requestProductsWithCompletionHandler(_ completionHandler: @escaping RequestProductsCompletionHandler) {
    self.completionHandler = completionHandler

    productsRequest = SKProductsRequest.init(productIdentifiers: productIdentifiers)
    productsRequest!.delegate = self
    productsRequest!.start()
  }

  // MARK: - Products request delegate

  func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    productsRequest = nil

    let skProducts = response.products
        for skProduct in skProducts {
            print("Found product: \(skProduct.productIdentifier), \(skProduct.localizedTitle), \(skProduct.price.floatValue)");
    }

    completionHandler!(true, skProducts)
    completionHandler = nil
  }

  func request(_ request: SKRequest, didFailWithError error: Error) {
        // NOTE: If this happens on the simulator, close the simulator window and re-run the app. This helps normally !!!
        print("Failed to load list of products. Error: \(error)")
    productsRequest = nil

    completionHandler!(false, nil)
    completionHandler = nil
  }

  // MARK: - Purchase

  func productPurchchased(_ productIdentifier:String) -> Bool {
    return purchasedProductIdentifiers!.contains(productIdentifier)
  }

  func buyProduct(_ product:SKProduct) {
        print("Buying \(product.productIdentifier)");

    let payment = SKPayment(product: product)
    SKPaymentQueue.default().add(payment)
  }

  func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
      switch transaction.transactionState {
      case SKPaymentTransactionState.purchased:
        self.completeTransaction(transaction)

      case SKPaymentTransactionState.failed:
        self.failedTransaction(transaction)

      case SKPaymentTransactionState.restored:
        self.restoreTransaction(transaction)

      default:
        print("Error: Unknown SKPaymentTransactionState")
      }
    }
  }

    func completeTransaction(_ transaction:SKPaymentTransaction) {
        print("completeTransaction...");

        self.provideContentForProductIdentifier(transaction.payment.productIdentifier)
        SKPaymentQueue.default().finishTransaction(transaction)
    }

    func restoreTransaction(_ transaction:SKPaymentTransaction) {
        print("restoreTransaction...");

        self.provideContentForProductIdentifier(transaction.original!.payment.productIdentifier)
        SKPaymentQueue.default().finishTransaction(transaction)
    }

    func failedTransaction(_ transaction:SKPaymentTransaction) {
        print("failedTransaction...");
        if let error = transaction.error as NSError?, error.code == SKError.paymentCancelled.rawValue {
                print("Transaction error:\(error.localizedDescription)");
        }

        SKPaymentQueue.default().finishTransaction(transaction)
    }

    func provideContentForProductIdentifier(_ productIdentifier:String) {

        purchasedProductIdentifiers?.insert(productIdentifier)
    UserDefaults.standard.set(true, forKey:productIdentifier)
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperProductPurchasedNotification), object: productIdentifier, userInfo: nil)
  }

  func restoreCompletedTransactions() {
    SKPaymentQueue.default().restoreCompletedTransactions()
  }

}

关于ios - Swift 中 SKProduct() 的应用内购买问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59707043/

相关文章:

ios - Flutter Http 请求未在 iOS 上执行

ios - 更改 uitabbar 项目图像的按钮

ios - "Thread 1: signal SIGTERM"在带有 iOS 的 xcode 中是什么意思?

android - Google Play 结算库 2.0.2 示例

ios - 您如何处理具有非 Apple 帐户系统的应用程序中的自动续订订阅?

ios - 在 iOS 中运行长任务时加载 "overlay"

android - 在多个 Android 设备上恢复购买

iphone - 交易错误: An unknown error has occurred During In App Purchased

ios - 自动更新内容的应用内购买提示用户分享信息

objective-c - NSLocale 货币符号,显示在金额之前或之后