Как я могу выдавать награды только после успешного завершения IAP

#swift #xcode #in-app-purchase

#swift #xcode #покупка в приложении

Вопрос:

Я постараюсь объяснить свою проблему как можно более четко. У меня есть IAP в моем приложении, я пытаюсь использовать логические значения, чтобы определить, должен ли игрок получать награды или нет. Я использую этот код

 self.purchaseExtraRounds = true
self.purchaseRemoveAds = true
  

но я не уверен, где его разместить, чтобы пользователь мог получать награды только после завершения покупки. На данный момент, где бы я его ни разместил, я могу щелкнуть по IAP, а затем нажать «Отмена», и награды будут включены без фактической покупки. Вот мой файл IAP manager.

 class IAPManager: NSObject {
  static let shared = IAPManager()
    var purchaseExtraRounds = false
    var purchaseRemoveAds = false
    
  private override init() {
    super.init()
  }
  
  func getProducts() {
    let request = SKProductsRequest(productIdentifiers: allInAppPurchases)
    request.delegate = self
    request.start()
  }
  
  func purchase(product: SKProduct) -> Bool {
    if !IAPManager.shared.canMakePayments() {
        return false
    } else {
      let payment = SKPayment(product: product)
        SKPaymentQueue.default().add(payment)
    }
    return true
  }

  func canMakePayments() -> Bool {
    return SKPaymentQueue.canMakePayments()
  }
}

extension IAPManager: SKProductsRequestDelegate, SKRequestDelegate {

  func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    let badProducts = response.invalidProductIdentifiers
    let goodProducts = response.products
    
    if !goodProducts.isEmpty {
      ProductsDB.shared.items = response.products
        print("Good", ProductsDB.shared.items)
    }
    
    print("Bad", badProducts)
  }
  
  func request(_ request: SKRequest, didFailWithError error: Error) {
    print("didFailWithError ", error)
    DispatchQueue.main.async {
      print("purchase failed")
    }
  }
  
    func requestDidFinish(_ request: SKRequest) {
    DispatchQueue.main.async {
      print("request did finish ")
    }
  }
}

final class ProductsDB: ObservableObject, Identifiable {
  static let shared = ProductsDB()
  var items: [SKProduct] = [] {
    willSet {
      DispatchQueue.main.async {
        self.objectWillChange.send()
      }
    }
  }
}
  

Я устал размещать код в нескольких местах в этом файле, но я натыкаюсь на стену.

Комментарии:

1. Вам необходимо отслеживать транзакции SKPaymentQueue с вашим наблюдателем и делать это после завершения платежной транзакции. Сделанный запрос на продукт еще не означает, что деньги будут выплачены.

Ответ №1:

Вам нужно будет начать наблюдение внутри AppDelegate, когда ваше приложение завершит запуск.

Вы должны вызвать

 SKPaymentQueue.default().add(self) //<< here comes your observer
  

внутри вашего IAPManager.

Тогда ваша функция purchase() может быть вызвана правильно. Затем примите

 SKPaymentTransactionObserver 
  

протокол, в котором вы можете реализовать следующий метод:

 func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
  

Здесь вы получаете свои транзакции и a transaction.transactionState , который указывает, была ли ваша транзакция успешной.

Возвращаясь к вашему первоначальному вопросу, если ваше состояние приобретено, вы установите свою переменную соответственно тому, какой продукт был куплен

Комментарии:

1. Спасибо @davidev теперь я понимаю, почему тогда у меня была эта проблема. До сих пор я реализовал этот код, но не получил никакого результата. Я добавил награду в состояние успешной покупки. мне потребуется некоторое время, чтобы разобраться в этом.

2. Хорошо, теперь я правильно реализую свой IAP, спасибо. У меня есть шесть элементов IAP, и я не уверен, как вызвать правильный метод для конкретного IAP, который был запрошен, когда он переходит в состояние purchased. Есть предложения? Вот список методов, которые я вызываю. case .purchased: removeAds() roundsx5() roundsx30() roundsx70() roundsx400() roundsx1000() SKPaymentQueue. default().finishTransaction(транзакция)

Ответ №2:

Итак, я решил проблему следующим образом; реализовать эту функцию

 private func handlePurchase(_ id: String) {
        if id == "remove ads product id" {
            removeAds(id: "remove ads product id")}
}
  

вызов на этом этапе

 case .purchased:
               handlePurchase(transaction.payment.productIdentifier)
  

который вызовет другую функцию, которую я создал, чтобы выдать награду следующим образом

 func removeAds(id: String) {
        UserDefaults.standard.set(true, forKey: "RemoveAdsPurchased")
    }