skip to Main Content

I will try and explain my issue as clearly as i can. I have IAP in my app, i am trying to use boolean values to determine if the player should receive rewards or not. I am using this code

self.purchaseExtraRounds = true
self.purchaseRemoveAds = true

but i am not sure where to place it to enable the user to get the rewards only after the purchase has been completed. At the moment wherever i seem to place it, i can click on a IAP and then click cancel and the rewards have been enabled without actually purchasing it. Here is my IAP manager file.

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

I have tired placing the code in several places in this file but i’m hitting a wall.

2

Answers


  1. Chosen as BEST ANSWER

    So i solved the issue like this; implement this function

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

    call at this point

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

    which will call another function i created to give the reward like so

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

  2. You will need to start observing inside AppDelegate when your App finished with launching.

    You have to call

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

    inside your IAPManager.

    Then your purchase() function can be called correctly. Then adopt the

    SKPaymentTransactionObserver 
    

    protocol, where you can implement the following method:

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

    Here you get your transactions, and a transaction.transactionState which indicates whether your transaction was successful.

    Back to your original question, if your state is purchased, you will set your variable accordingly which product was bought

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search