iosin-app-purchasenon-renewing-subscription

why non-renewing subscription, shows "This In-App purchase has already been bought. It will be restored for free.", when purchasing item again?


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.


Solution

  • 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.