Products

Before you can offer any items for sale, your application needs to fetch detailed product information from the Onside servers. This is done using the unique SKU (product identifier) for each product, which you can find in the Onside Developer Console.

The process involves creating a request object, starting it, and handling the results through a delegate.

The Fetching Process: An Overview

  1. Create a Request: Use Onside.makeProductsRequest(productIdentifiers:) to create a request object for a specific set of SKUs.

  2. Assign a Delegate: Set a delegate object that will receive the success or failure callbacks.

  3. Retain and Start: Keep a strong reference to the request object and call its start() method to begin the fetch.

  4. Handle the Response: Implement the delegate methods to receive the product data or handle any errors.

Step 1: Creating and Starting a Products Request

To begin, you create an OnsideProductsRequest instance and then start it.

Important: You must retain a strong reference to the OnsideProductsRequest object for the duration of the request. If the object is deallocated, the network request will be automatically cancelled.

import UIKit
import OnsideKit

class ProductsViewController: UIViewController {

    private var productsRequest: OnsideProductsRequest?
    private var availableProducts: [OnsideProduct] = []

    func fetchProducts() {
        // A set of product SKUs you want to fetch from the Onside backend.
        let productSKUs: Set<String> = [
            "com.yourapp.premium_feature",
            "com.yourapp.subscription.monthly"
        ]

        // 1. Create the request object.
        let request = Onside.makeProductsRequest(productIdentifiers: productSKUs)

        // 2. Set the delegate to receive callbacks.
        request.delegate = self

        // 3. Retain the request object to prevent it from being deallocated.
        self.productsRequest = request

        // 4. Start the network request.
        request.start()
    }
}

Step 2: Handling the Response with OnsideProductsRequestDelegate

To receive the results of the request, your class (e.g., your view controller) must conform to the OnsideProductsRequestDelegate protocol and implement its methods.

extension ProductsViewController: OnsideProductsRequestDelegate {

    // --- Required Delegate Methods ---

    // Called on success, delivering the response object.
    func onsideProductsRequest(
        _ request: OnsideProductsRequest,
        didReceive response: OnsideProductsResponse
    ) {
        // The response contains valid products you can display and sell.
        self.availableProducts = response.products
        
        // It also contains any identifiers that were requested but not found.
        if !response.invalidProductIdentifiers.isEmpty {
            print("Could not find products for SKUs: \(response.invalidProductIdentifiers)")
        }

        // Update your UI to display the fetched products.
        self.tableView.reloadData()
    }

    // Called if the request fails for any reason (e.g., network error).
    func onsideProductsRequest(
        _ request: OnsideProductsRequest,
        didFailWithError error: OnsideProductsRequestError
    ) {
        print("Failed to fetch products with error: \(error.localizedDescription)")
    }
    
    // --- Optional Delegate Method ---

    // Called after the request has finished, either in success or failure.
    // This is a good place for cleanup.
    func onsideProductsRequestDidFinish(_ request: OnsideProductsRequest) {
        print("Products request finished.")
        self.productsRequest = nil
    }
}

Delegate Methods Explained

  • onsideProductsRequest(_:didReceive:) This is the primary success callback. The OnsideProductsResponse object it provides contains two key properties:

    • products: An array of OnsideProduct objects that are valid and available for purchase.

    • invalidProductIdentifiers: A Set of Strings for any SKUs you requested that could not be found or are not available in the user's region.

  • onsideProductsRequest(_:didFailWithError:) This method is called if a non-recoverable error occurs during the fetch, such as a loss of network connectivity or an issue with the user's session.

  • onsideProductsRequestDidFinish(_:) This method is always called when the request sequence concludes (after a success or failure). While its implementation is often not required, it is the ideal place for cleanup tasks.

⚠️ Handling Regions and Product Availability

Product availability and pricing can vary based on the user's region. OnsideKit is designed to handle this complexity, but it's important to understand how it works to provide the best user experience.

Fetching Products Before Login

You can and should fetch products even before a user is authenticated. This allows you to display your store UI and promote your offerings as soon as the user opens the app.

When fetching products for a logged-out user, OnsideKit determines the region as follows:

  1. It first checks if you have implemented the onsideDefaultCountryCodeAssumption() delegate method. If you provide a country code here, it will be used. This is the best way to provide an accurate "guess" if your app has other knowledge of the user's location.

  2. If the delegate method returns nil, the SDK will fall back to using the device's system region.

Best Practice: Re-fetch Products After Login/Logout

The user's true region is determined by their Onside account after they log in. This may differ from the region that was assumed when they were logged out.

Important: It is crucial to re-fetch your product list whenever the user's authentication status changes. The most reliable way to detect this is to observe changes to the user's storefront. When a user logs in or out, the Onside.paymentQueue().storefront will change (from nil to a value, or vice-versa). You should trigger a new product request at this point to ensure your UI displays the correct products and prices for the authenticated user.

How the SDK Protects Users During Purchase

What happens if a user starts a purchase for a product that was fetched for one region, but their account is in another? For example:

  1. A user in Germany (system region) opens your app. Products are fetched with German pricing.

  2. The user decides to buy an item and taps "Buy."

  3. The SDK triggers the login flow. The user logs into their account, which is registered in Spain.

  4. The price or availability of the item is different in Spain.

OnsideKit has a built-in safety mechanism to handle this scenario gracefully:

  • The product will not be purchased automatically at the new price.

  • Instead, the SDK will present a dedicated UI that clearly informs the user of the price change (e.g., "The price has changed from €9.99 to $10.99") or that the product is no longer available in their region.

  • Explicit confirmation is required from the user to proceed with the purchase at the new price.

This ensures a transparent and fair experience, building trust with your users.

Last updated

Was this helpful?