В проблеме покупки приложения с SKProduct() в Swift

Я пытаюсь внедрить покупки в приложении в приложение, которое я создаю, однако, когда я пытаюсь «получить» продукт, который у меня есть 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 здесь


person Thomas Braun    schedule 12.01.2020    source источник


Ответы (2)


Ваша функция 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()
  }

}
person Reinhard Männer    schedule 12.01.2020

Для получения товаров необходимо произвести SKProductsRequest и дождаться ответа в SKProductsRequestDelegate способах.

Создайте и запустите запрос:

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

Где ids должно быть Set<String> ваших идентификаторов продуктов.

Соответствовать 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
    }
}
person duckoteka    schedule 15.01.2020