[Swift] Implementation of ultra-simple billing

I tried to summarize the implementation of billing that I find difficult. It's very easy to copy and implement. I would be happy if you could use it while customizing it as needed.

Whole implementation

StoreManager.swift

Commentary

class StoreManager: NSObject, SKPaymentTransactionObserver {
    static var sharedStore = StoreManager()
    var products: [SKProduct] = []

    //Define a list of product ids
    let productsIdentifiers: Set<String> = []

    //Call AppDelegate or before billing to get a list of products
    static func setup() {
        sharedStore.validateProductsIdentifiersWithRequest()
    }
    
    //Get product information from Store
    private func validateProductsIdentifiersWithRequest() {
        let request = SKProductsRequest(productIdentifiers: productsIdentifiers)
        request.delegate = self
        request.start()
    }
    ...
}

Get product information

--Define the Product ID of the billing item created in App Store Connect.

//Define a list of productId
//Product ID is sample.For id
let productsIdentifiers: Set<String> = ["sample.id"]

-Get a list of Product information based on the defined productsIdentifiers.

//Get product information from Store
private func validateProductsIdentifiersWithRequest() {
    //Request for acquisition
    let request = SKProductsRequest(productIdentifiers: productsIdentifiers)
    request.delegate = self
    request.start()
}

//The result of the acquisition process is`SKProductsRequestDelegate`Will be notified to
extension StoreManager: SKProductsRequestDelegate {
    //Product information acquisition completed
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        products = response.products
    }
}

Purchase request

//Purchase
func purchaseProduct(_ productIdentifier: String) {
    //Check if there is product information corresponding to productIdentifier
    guard let product = productForIdentifiers(productIdentifier) else { return }
    //Purchase request
    let payment = SKPayment(product: product)
    SKPaymentQueue.default().add(payment)
}

//Check if the corresponding product information exists in products
private func productForIdentifiers(_ productIdentifier: String) -> SKProduct? {
    return products.filter({ (product: SKProduct) -> Bool in
        return product.productIdentifier == productIdentifier
    }).first
}

Purchase request Transaction

//Called every time transactions change
//Describe the content you want to process according to the state of Transaction
//Note that when you end a transaction, the consumable receipt disappears and the Transaction cannot be restored.
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        switch transaction.transactionState {
        case .purchasing:
            //Added to queue
        case .purchased:
            //Purchase completed
        case .restored:
            //Restoration from purchase history completed
        case .deferred:
            //Purchase processing is pending and approved town
        case .failed:
            //Request failed before being queued
        default:
            break
        }
    }
}

About Transactions and Receipts

A receipt will be generated on Apple's server once the billing is complete. When verifying receipts, be aware that if you close Transaction, consumable receipts will be deleted and you will not be able to earn income. Subscription receipts, etc. can be obtained all the time even when Transaction is closed, so be careful not to create multiple receipts when verifying receipts and creating data.

What is .deferred?

When you try to make a purchase with an account that has "Ask to Buy" enabled, your purchase will be suspended and you will be notified by the administrator asking for permission. The Transaction state will be .deferred until the notification is granted. This is due to the Family Sharing (https://www.apple.com/jp/family-sharing/) feature.

Related article

[IOS] The location of the Sand Box account has changed in iOS 14

Recommended Posts

[Swift] Implementation of ultra-simple billing
[Swift 5] Implementation of membership registration with Firebase
Implementation of GKAccessPoint
SKStoreReviewController implementation memo in Swift UI of iOS14
Implementation of flash messages
Implementation of search function
Applied implementation of chat-space
Implementation of pagination function
[Swift] This is the solution! Illustration of Delegate implementation
Rails implementation of ajax removal
[Swift] Types of types-Basic knowledge-
Implementation of sequential search function
Implementation of like function (Ajax)
[Rails 6] Implementation of search function
Implementation of image preview function
[Java] Implementation of Faistel Network
Implementation of XLPagerTabStrip with TabBarController
[Rails] Implementation of category function
Implementation of category pull-down function
Implementation of unit test code
Implementation of gzip in java
[Rails] Implementation of tutorial function
[Rails] Implementation of like function
Implementation of tri-tree in Java
Implementation of HashMap in kotlin
[Rails] Implementation of user logic deletion
[Rails] Implementation of CSV import function
[Rails] Asynchronous implementation of like function
Implementation of ls command in Ruby
[Swift] Change the textColor of UIDatePicker
Easy implementation of Android file browsing
[Swift] Acquisition of IDFA on iOS14
[Rails] About implementation of like function
[Rails] Implementation of user withdrawal function
[Rails] Implementation of CSV export function
The basic basis of Swift dialogs
Implementation of asynchronous processing in Tomcat
[Swift] Advantages and disadvantages of Storyboard
Implementation of validation using regular expressions
[Rails] Implementation of many-to-many category functions
Animated display of Swift error messages
Default implementation of Object.equals () and Object.hashCode ()
Implementation of like function in Java