【问题标题】:In App Purchase issue with SKProduct() in Swift在 Swift 中使用 SKProduct() 的应用购买问题
【发布时间】:2020-04-29 14:25:27
【问题描述】:

我正在尝试将应用内购买实现到我正在创建的应用中,但是当我尝试“获取”我拥有的产品时 var products = [SKProducts]() 但是这会返回一个空数组,导致应用程序崩溃。 我已经检查了所有税收协议等,当我在应用程序购买示例项目中的苹果中测试它时,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

【问题讨论】:

    标签: ios in-app-purchase storekit


    【解决方案1】:

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

    【讨论】:

    • 如何初始化didFinishLaunchingWithOptions 中的IAPhelper 类?你也能证明这一点吗?我遇到了购买中断的问题,并且在用户重新启动应用程序或让应用程序进入后台然后返回前台之前,购买的商品不会显示
    【解决方案2】:

    要获得产品,您必须制作 SKProductsRequest 并在 SKProductsRequestDelegate 方法中等待答案。

    创建并启动请求:

    let request = SKProductsRequest(productIdentifiers: ids)
    request.delegate = self // self is delegate of SKProductsRequestDelegate, see below
    request.start()
    

    ids 必须是 Set&lt;String&gt; 的产品标识符。

    符合SKProductsRequestDelegate:

    extension MyClass: SKProductsRequestDelegate {
    
        internal func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
            print(response.products) // here is your [SKProduct] array
            print(response.invalidProductIdentifiers) // if you put wrong ids they would be here
        } 
    
        internal func request(_ request: SKRequest, didFailWithError error: Error) {
            print(error) // something wrong
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 2014-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多