Article

Processing a Transaction

Register a transaction queue observer to get and handle transaction updates from the App Store.

Overview

Implementing an in-app purchase flow can be divided into three stages. You first retrieve the product information, then send a payment request by adding it to the payment queue. Finally, your app delivers the products for successful transactions. This article details the steps performed by your app and the App Store in the last stage, as highlighted in Figure 1.

The App Store calls the transaction queue observer after it processes the payment request. Your app then records information about the purchase for future launches, downloads the purchased content, and marks the transaction as finished.

Figure 1

Complete the purchase process by monitoring the transaction queue to deliver products

A flow chart depicting the steps of the in-app purchase process. The delivering content stage is diagrammed as three steps between your app and the App Store. First, the App Store processes the payment; next, the App Store calls your app's transaction queue observer; and finally, your app delivers the purchased product.

Monitor Transactions in the Queue

The transaction queue plays a central role in letting your app communicate with the App Store through the StoreKit framework. You add work to the queue that the App Store needs to act on, such as a payment request to be processed. When the transaction’s state changes, such as when a payment request succeeds, StoreKit calls the app’s transaction queue observer. You decide which class acts as the observer. In very small apps, you could handle all the StoreKit logic in the app delegate, including observing the transaction queue. In most apps, however, you create a separate class that handles this observer logic along with the rest of your app’s store logic. The observer must conform to the SKPaymentTransactionObserver protocol.

By adding an observer, your app does not need to constantly poll the status of its active transactions. Your app uses the transaction queue for payment requests, to download Apple-hosted content, and to find out that subscriptions have been renewed.

Always register a transaction queue observer as soon as your app is launched, as shown below. For more guidance, see Setting Up the Transaction Observer and Payment Queue.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    /* ... */
    SKPaymentQueue.default().add(observer)
    return true
}

Make sure that the observer is ready to handle a transaction at any time, not only after you add a transaction to the queue. For example, if a user buys something in your app right before going into a tunnel, your app may not be able to deliver the purchased content if there is no network connection. The next time your app launches, StoreKit calls your transaction queue observer again and your app should handle the transaction and deliver the purchased content. Similarly, if your app fails to mark a transaction as finished, StoreKit calls the observer every time your app launches until the transaction finishes.

Implement the paymentQueue(_:updatedTransactions:) method on your transaction queue observer. StoreKit calls this method when the status of a transaction changes, such as when a payment request has been processed. The transaction status tells you what action your app needs to perform, as described in Table 1.

Table 1

Transaction statuses and corresponding actions

Status

Action to take in your app

SKPaymentTransactionState.purchasing

Update your UI to reflect the in-progress status, and wait to be called again.

SKPaymentTransactionState.deferred

Update your UI to reflect the deferred status, and wait to be called again.

SKPaymentTransactionState.failed

Use the value of the error property to present a message to the user. For a list of error constants, see SKErrorDomain.

SKPaymentTransactionState.purchased

Provide the purchased functionality, typically by unlocking features or delivering content.

SKPaymentTransactionState.restored

Restore the previously purchased functionality.

Transactions in the queue can change state in any order. Your app needs to be ready to work on any active transaction at any time. Act on every transaction according to its transaction state, as in this example:

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
     for transaction in transactions {
     switch transaction.transactionState {
          // Call the appropriate custom method for the transaction state.
     case .purchasing: showTransactionAsInProgress(transaction, deferred: false)
     case .deferred: showTransactionAsInProgress(transaction, deferred: true)
     case .failed: failedTransaction(transaction)
          case .purchased: completeTransaction(transaction)
     case .restored: restoreTransaction(transaction)
          // For debugging purposes.
     @unknown default: print("Unexpected transaction state \(transaction.transactionState)")
    }
     }
}

Update the App's UI to Reflect Transaction Changes

To keep your user interface up to date while waiting, the transaction queue observer can implement optional methods from the SKPaymentTransactionObserver protocol as follows:

For successfully processed transactions, your app should validate the receipt associated with the transaction to verify the items purchased by the user and unlock content accordingly.

See Also

Delivering Content

class SKDownload

Downloadable content associated with a product.

class SKReceiptRefreshRequest

A request to refresh the receipt, which represents the user's transactions with your app.

class SKRequest

An abstract class that represents a request to the App Store.

class SKPaymentTransaction

An object in the payment queue.

func SKTerminateForInvalidReceipt()

Terminates an app if the license to use the app has expired.