Tagged with: Swift, iOS
696 words; 3 minutes to read.
Adding In-App Purchases (IAP) to your app can enhance user experience and generate revenue. Here’s a step-by-step guide to setting up IAP in App Store Connect.
There are two types of In-App Purchases:
Once you’ve filled in the necessary details, save your product. If the system doesn’t automatically take you to the next page, click on your newly saved IAP.
Here, you need to set various options:
Review Information:It’s crucial to fill this section extensively. Detailed information here will help ensure that your review passes the check immediately.
Now let’s move on to the code side of things.
1. Track User Purchases:
Create an observable object to track important behaviors in the app, such as the type of user (free or premium).
class ApplicationState: ObservableObject {
@Published var route: AppRouter = .splash
@Published var isPremiumUser: Bool = false
}
And here is IAP manager that can help anyone as a starting point.
import Foundation
import StoreKit
class IAStoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
@Published var products: [SKProduct] = []
@Published var purchasedProductIdentifiers: Set = []
override init() {
super.init()
loadPurchasedProducts()
SKPaymentQueue.default().add(self)
fetchProducts()
}
deinit {
SKPaymentQueue.default().remove(self)
}
func fetchProducts() {
let productIdentifiers = Set(["your_product_id"])
let request = SKProductsRequest(productIdentifiers: productIdentifiers)
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async {
self.products = response.products
}
}
func request(_ request: SKRequest, didFailWithError error: any Error) {
print(error)
}
func requestDidFinish(_ request: SKRequest) { }
func purchase(product: SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
SKPaymentQueue.default().finishTransaction(transaction)
savePurchasedProduct(identifier: transaction.payment.productIdentifier)
loadPurchasedProducts()
case .failed:
SKPaymentQueue.default().finishTransaction(transaction)
case .restored:
SKPaymentQueue.default().finishTransaction(transaction)
savePurchasedProduct(identifier: transaction.payment.productIdentifier)
loadPurchasedProducts()
case .deferred, .purchasing:
break
@unknown default:
break
}
}
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) {
DispatchQueue.main.async {
NotificationCenter.default.post(name: .restoreFailed, object: error.localizedDescription)
}
}
func restorePurchases() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
private func savePurchasedProduct(identifier: String) {
var purchasedProducts = UserDefaults.standard.array(forKey: "purchasedProducts") as? [String] ?? []
purchasedProducts.append(identifier)
UserDefaults.standard.set(purchasedProducts, forKey: "purchasedProducts")
}
private func loadPurchasedProducts() {
let purchasedProducts = UserDefaults.standard.array(forKey: "purchasedProducts") as? [String] ?? []
purchasedProductIdentifiers = Set(purchasedProducts)
}
}