A differenza degli abbonamenti ricorrenti, i **prodotti consumabili** (come i pacchetti di minuti per chiamate internazionali o i gettoni di ricarica wallet) possono essere acquistati ripetutamente dagli utenti. **StoreKit 2** su iOS fornisce un'API basata su async/await dotata di crittografia JWS (JSON Web Signature) nativa per la verifica immediata delle ricevute.
1. Identificativi dei Prodotti Consumabili ed Identificazione del Carrier
In un'app di telefonia come **Africall**, i pacchetti di minuti sono spesso legati all'operatore di destinazione (es. koracall.minutes.ml.orange.30 per 30 minuti Orange Mali). Definiamo gli ID in una struct Swift:
import Foundation
import StoreKit
enum StoreKitProducts {
static let minutePacks: Set = [
"koracall.minutes.ml.orange.30",
"koracall.minutes.ml.orange.60",
"koracall.minutes.sn.orange.120",
"koracall.minutes.it.mobile.300"
]
}
2. Caricamento ed Esecuzione dell'Acquisto in Swift
StoreKit 2 rende l'invocazione dell'acquisto ed il controllo dei risultati estremamente compatto e sicuro:
import SwiftUI
import StoreKit
class WalletStoreManager: ObservableObject {
@Published var availableProducts: [Product] = []
@Published var isPurchasing: Bool = false
func fetchProducts() async {
do {
let products = try await Product.products(for: StoreKitProducts.minutePacks)
DispatchQueue.main.async {
self.availableProducts = products.sorted(by: { $0.price < $1.price })
}
} catch {
print("Errore caricamento prodotti StoreKit 2: \(error)")
}
}
func purchaseProduct(_ product: Product) async throws {
DispatchQueue.main.async { self.isPurchasing = true }
let result = try await product.purchase()
switch result {
case .success(let verification):
// Verifica crittografica del JWS inviato da Apple
let transaction = try checkVerified(verification)
// Accredito del pacchetto di minuti sul server backend / Firestore
try await creditMinutesToUserWallet(transaction: transaction)
// Notifica ad Apple che la transazione consumabile è stata consegnata
await transaction.finish()
DispatchQueue.main.async { self.isPurchasing = false }
case .userCancelled, .pending:
DispatchQueue.main.async { self.isPurchasing = false }
@unknown default:
DispatchQueue.main.async { self.isPurchasing = false }
}
}
private func checkVerified(_ result: VerificationResult) throws -> T {
switch result {
case .unverified(_, let error):
throw error
case .verified(let safe):
return safe
}
}
private func creditMinutesToUserWallet(transaction: Transaction) async throws {
print("Transazione verificata ID: \(transaction.id). Invio accredito al backend...")
}
}
3. UI del Wallet ed In-App Storefront in SwiftUI
Possiamo costruire una schermata di ricarica wallet nativa in SwiftUI con i componenti ufficiali StoreView o card personalizzate:
struct WalletRechargeView: View {
@StateObject private var store = WalletStoreManager()
var body: some View {
VStack {
Text("Ricarica Wallet Minuti")
.font(.title2)
.bold()
if store.isPurchasing {
ProgressView("Elaborazione acquisto sicuro Apple...")
}
List(store.availableProducts, id: \.id) { product in
HStack {
VStack(alignment: .leading) {
Text(product.displayName).bold()
Text(product.description).font(.caption).foregroundColor(.gray)
}
Spacer()
Button(product.displayPrice) {
Task {
try? await store.purchaseProduct(product)
}
}
.buttonStyle(.borderedProminent)
}
}
}
.task {
await store.fetchProducts()
}
}
}
Conclusione
StoreKit 2 elimina le complessità dei vecchi ricevuti base64 garantendo transazioni consumabili a prova di contraffazione. Per assistenza nell'integrazione di StoreKit 2 nelle tue app iOS, scrivi a diallooyunus@gmail.com.