1

I am implementing the non renewable purchase in my app. I am still using in sandbox mode. After I subscribe for the product, when I again try to subscribe the same product, it gives me an alert saying ‘This In-App purchase has already been bought. It will be restored for free.’. I don’t know how I should enable user to subscribe again.

How can I handle multiple user on same device? If one user has paid for the subscription and another user log in into same device to my application he/she should not get the alert as above.

Code : 

import StoreKit
class className: SKProductsRequestDelegate
{
    var productIDs: Array<String?> = []
    var productsArray: Array<SKProduct?> = []

   override func viewDidLoad(){
       // product IDs for in-app purchase products
        productIDs.append(“monthly_subscription_id”) // Monthly
        productIDs.append(“yearly_subscription_id”) // Year
        requestProductInfo()
        SKPaymentQueue.default().add(self)
     }
     func requestProductInfo() {
            if SKPaymentQueue.canMakePayments() {
             let productIdentifiers = NSSet(array: productIDs)
                let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as    Set<NSObject> as! Set<String>)
                productRequest.delegate = self
             productRequest.start()
         }
            else {
                print("Cannot perform In App Purchases.")
              }
    }   
    // MARK: SKProductsRequestDelegate method implementation
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        if response.products.count != 0 {
            for product in response.products {
                productsArray.append(product )
            }
        }
        else {
            print("There are no products.")
        }
        if response.invalidProductIdentifiers.count != 0 {
            print(response.invalidProductIdentifiers.description)
        }
    }
// MARK: Buy Subscription button action
@IBAction func btn_purchase_Action(_ sender: Any){
        let payment = SKPayment(product: self.productsArray[productIndex]!)
        SKPaymentQueue.default().add(payment)
        self.transactionInProgress = true
    }
}

// MARK: - SKPaymentTransactionObserver
extension className: SKPaymentTransactionObserver {
    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]){
        for transaction in transactions {
            switch (transaction.transactionState) {
            case .purchased:
                complete(transaction: transaction)
                break
            case .failed:
                fail(transaction: transaction)
                break
            case .restored:
                restore(transaction: transaction)
                break
            case .deferred:
                break
            case .purchasing:
                break
            }
        }
    }
    private func complete(transaction: SKPaymentTransaction){
        print("complete...")
        SKPaymentQueue.default().finishTransaction(transaction)
    }
    private func restore(transaction: SKPaymentTransaction){
        guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
        print("restore... \(productIdentifier)")
        SKPaymentQueue.default().finishTransaction(transaction)
    }
    private func fail(transaction: SKPaymentTransaction){
        print("fail...")
        if let transactionError = transaction.error as? NSError {
            if transactionError.code != SKError.paymentCancelled.rawValue {
                print("Transaction Error: \(transaction.error?.localizedDescription)")
            }
        }
        SKPaymentQueue.default().finishTransaction(transaction)
    }
}

I could see popup saying in-app purchase is successful, but "updatedTransaction" function is not called when i successfully finish in-app purchase process. First time in-app purchase is completed but when i try to purchase the same product again it shows the alert that product is already purchased and could restore for free.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
Krishna Maru
  • 164
  • 13
  • You need to show some code. Do you correctly complete the purchase transaction? – Paulw11 Mar 26 '18 at 18:51
  • @Paulw11, i have edited my question with code i have used, in it. thanks – Krishna Maru Mar 27 '18 at 05:15
  • Are you certain that your product is defined as a non-auto renewing subscription? – Paulw11 Mar 27 '18 at 05:26
  • @Paulw11 yes, its Non-Renewing subscription only. see the link : https://prnt.sc/iwvntb – Krishna Maru Mar 27 '18 at 05:53
  • You say that `updatedTransactions` is not called; Is the object that is your payment queue observer being released? From your code it looks like it is a view controller. If the view controller is dismissed before the payment transaction has been processed then you won't get a chance to complete the transaction. Your payment queue observer should be an object that is instantiated as soon as your app launches and remains in memory for the lifetime of your app. Creating the payment queue observer in `didFinishLaunching` and holding a reference to it in your app delegate is a good approach – Paulw11 Mar 27 '18 at 06:02
  • @Paulw11, Yes, its a viewController where i have plans(for which i have implemented in-app). so are you saying that other than in this viewController i need to add SKPaymentQueue.default().add(self) method in didFinishLaunching & methods for this in appDelegate. so if the transaction is not yet completed before i leave my viewController, its finish event will detected in appdelegate when i launch the app again? is that so ? – Krishna Maru Mar 27 '18 at 06:17
  • Yes. It is also possible that there is a pending transaction that needs to be completed when the app launches, so you should create the transaction observer as soon as possible as payment transactions can arrive at any time – Paulw11 Mar 27 '18 at 06:20
  • @Paulw11, I did same as you told and it works now. Thanks a lot. – Krishna Maru Mar 27 '18 at 06:59

1 Answers1

0

From your code it looks like your transaction observer is a view controller.

If the view controller is dismissed before the payment transaction has been processed then you won't get a chance to complete the transaction.

Your payment queue observer should be an object that is instantiated as soon as your app launches and remains in memory for the lifetime of your app.

Creating the payment queue observer in didFinishLaunching and holding a reference to it in your app delegate is one approach that you can use.

Paulw11
  • 108,386
  • 14
  • 159
  • 186