Class

SKStorefront

An object containing the location and unique identifier of an Apple App Store storefront.

Declaration

class SKStorefront : NSObject

Overview

In-app products you create through App Store Connect are available for sale in every region with an App Store. You can use the storefront information to determine the customer's region, and offer in-app products suitable for that region. StoreKit exposes SKStorefront storefront information as a read-only property in SKPaymentQueue.

You must maintain your own list of product identifiers and the storefronts in which you want to make them available.

Show Products Based on the Current Storefront

The following example function shouldShow returns false if your product is not suitable for the given storefront. You must create your own list of products available by storefront, referred to as myProducts in Listing 1.

Listing 1

Use the storefront value to determine if your app should display a product

func shouldShow(_ productIdentifier: String, in storefront: SKStorefront) -> Bool {
    var shouldShow = true
     
    // myProducts is a dictionary representing your own metadata for products,
    // keyed on an SKProduct.productIdentifier.
    if let myProduct = myProducts[productIdentifier] {
        shouldShow = myProduct.countryCodes.contains(storefront.countryCode)
    }
    return shouldShow
}

Listing 2 requests information for products that you wish to display based on the device's storefront. It uses the shouldShow function defined in Listing 1.

Listing 2

Request product information for the products to display

func fetchProductInfo() {
    var identifiers = Set<String>()
    if let storefront = SKPaymentQueue.default().storefront {
        for (identifier, _) in myProducts {
            if shouldShow(identifier, in: storefront) {
                identifiers.insert(identifier)
            }
        }
        let request = SKProductsRequest(productIdentifiers: identifiers)
        request.delegate = self
        request.start()
    }
}

Listen for Storefront Changes

The storefront value can change at any time. To listen for changes in this value, implement the paymentQueueDidChangeStorefront(_:) method. Refresh the list of your available products when the storefront changes, as shown in Listing 3. The shouldShow function is defined in Listing 1.

Listing 3

Listen for storefront changes in the transaction observer

func paymentQueueDidChangeStorefront(_ queue: SKPaymentQueue) {
    if let storefront = queue.storefront {
        // Refresh the displayed products based on the new storefront.
        for product in storeProducts {
            if shouldShow(product.productIdentifier, in: storefront) {
                // Display this product in your store UI.
         }
      }
   }
}

Respond to Storefront Changes

The current storefront can change at any time, including during a transaction. Listing 4 determines whether the transaction should continue in the updated storefront. Your delegate's paymentQueue(_:shouldContinue:in:) method must return quickly, before the call times out. The shouldShow function is defined in Listing 1.

Listing 4

Determine whether to continue a transaction in an updated storefront

SKPaymentQueue.default().delegate = self  // Set your object as the SKPaymentQueue delegate.

func paymentQueue(_ paymentQueue: SKPaymentQueue,
                  shouldContinue transaction: SKPaymentTransaction,
                  in newStorefront: SKStorefront) -> Bool {
    return shouldShow(transaction.payment.productIdentifier, in: newStorefront)
}

If the product isn't available in the updated storefront, the transaction fails with the error SKError.Code.storeProductNotAvailable. Handle this error in your paymentQueue(_:updatedTransactions:) method by displaying an alert to let the user know why the app can't complete the transaction, as shown in Listing 5.

Listing 5

Display an alert if a product is not available in an updated storefront

func paymentQueue(_ queue: SKPaymentQueue,
                  updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        if let transactionError = transaction.error as NSError?,
            transactionError.domain == SKErrorDomain
            && transactionError.code == SKError.storeProductNotAvailable.rawValue {
            // Show an alert.
        }
    }
}

Topics

Identifying the Storefront

var countryCode: String

The three-letter code representing the country associated with the App Store storefront.

var identifier: String

A value defined by Apple that uniquely identifies an App Store storefront.

Relationships

Inherits From

Conforms To