1

The SKPaymentTransactionObserver.paymentQueue:updatedTransactions returns a array of transactions. When I make a payment, how do I know which transaction is the payment I made? Does it always return one transaction when I make a payment?

Meanwhile, this observer function is also called when restoring transactions. So, what is the best practice to handle the updatedTransactions?

BTW, my subscription product is a auto-renew subscription.

jarly
  • 231
  • 1
  • 4
  • 16

1 Answers1

2

iterate through the loop of the transactions and check for each transaction.

    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch (transaction.transactionState) {
            case .purchased:
                completeTransaction(transaction: transaction)
                break
            case .failed:
                failedTransaction(transaction: transaction)
                break
            case .restored:
                restoreTransaction(transaction: transaction)
                break
            case .deferred:
                // TODO show user that is waiting for approval

                break
            case .purchasing:
                break
            }
        }
    }

    private func completeTransaction(transaction: SKPaymentTransaction) {

        print("completeTransaction...")

        deliverPurchaseForIdentifier(identifier: transaction.payment.productIdentifier)
        SKPaymentQueue.default().finishTransaction(transaction)

    }

    private func restoreTransaction(transaction: SKPaymentTransaction) {


        guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }

        print("restoreTransaction... \(productIdentifier)")


        deliverPurchaseForIdentifier(identifier: productIdentifier)
        SKPaymentQueue.default().finishTransaction(transaction)
    }

    private func failedTransaction(transaction: SKPaymentTransaction) {

        if let error = transaction.error as NSError? {
            if error.domain == SKErrorDomain {
                // handle all possible errors
                switch (error.code) {
                case SKError.unknown.rawValue:
                    print("Unknown error")

                    BaseViewController.currentViewController?.Alert(title: MFErrors.purchaseFaild.messgae.title, msg: MFErrors.purchaseFaild.messgae.body)

                case SKError.clientInvalid.rawValue:
                    print("client is not allowed to issue the request")

                    BaseViewController.currentViewController?.Alert(title: MFErrors.accountNotAllowedToMakePurchase.messgae.title, msg: MFErrors.accountNotAllowedToMakePurchase.messgae.body)

                case SKError.paymentCancelled.rawValue:
                    print("user cancelled the request")

                case SKError.paymentInvalid.rawValue:
                    print("purchase identifier was invalid")

                case SKError.paymentNotAllowed.rawValue:
                    print("this device is not allowed to make the payment")
                    BaseViewController.currentViewController?.Alert(title: MFErrors.purchaseFaild.messgae.title, msg: MFErrors.purchaseFaild.messgae.body)
                default:
                    break;
                }
            }

            ProgressViewManager.shared.hide()
        }

        SKPaymentQueue.default().finishTransaction(transaction)
    }

    private func deliverPurchaseForIdentifier(identifier: String?) {

        guard let identifier = identifier else { return }

       //Check if this transactions is a subscription
       //SubscriptionsProductIdentifiers is an array of subscriptions product ids you sent to the app store to get SKProducts

        //If subscription
        if SubscriptionsProductIdentifiers.contains(identifier) {


        }else{
           //If non-consumable, consumables etc... 

        }


    }

here's complete Store Manager in my previous answer: How to handle shouldAddStorePayment for In-App Purchases in iOS 11?

Jad
  • 2,139
  • 1
  • 16
  • 28
  • if all these transactions are of same products, how do i know which one is the latest? and, which one is for the payment I made just now? – jarly Nov 20 '17 at 10:12
  • First you can save the product id the user decided to purchase and then you will know which product by comparing the saved product id with the identifier in the example above, but this is not enough you will anyway need to send the receipts for validation to Apple server to get the receipt decoded to JSON and have all the information for each subscription, such as purchase date and expiry date and so on. – Jad Nov 20 '17 at 14:36