parent
e40f9d672f
commit
0ab3149980
@ -0,0 +1,111 @@ |
||||
// |
||||
// Store.swift |
||||
// Poker Analytics 6 |
||||
// |
||||
// Created by Laurent Morvillier on 20/04/2022. |
||||
// |
||||
|
||||
import Foundation |
||||
import StoreKit |
||||
|
||||
//public enum StoreError: Error { |
||||
// case failedVerification |
||||
//} |
||||
|
||||
protocol StoreDelegate { |
||||
func productsReceived() |
||||
func errorDidOccur(error: Error) |
||||
} |
||||
|
||||
//extension Notification.Name { |
||||
// static let StoreEventHappened = Notification.Name("storePurchaseSucceeded") |
||||
//} |
||||
|
||||
class Store: ObservableObject { |
||||
|
||||
@Published private(set) var products: [Product] = [] |
||||
|
||||
@Published private(set) var purchasedTransactions = Set<StoreKit.Transaction>() |
||||
|
||||
var delegate: StoreDelegate? = nil |
||||
|
||||
var updateListenerTask: Task<Void, Error>? = nil |
||||
|
||||
init() { |
||||
|
||||
self.updateListenerTask = listenForTransactions() |
||||
|
||||
Task { |
||||
//Initialize the store by starting a product request. |
||||
await self.requestProducts() |
||||
} |
||||
} |
||||
|
||||
deinit { |
||||
self.updateListenerTask?.cancel() |
||||
} |
||||
|
||||
func indexOf(identifier: String) -> Int? { |
||||
return self.products.map { $0.id }.firstIndex(of: identifier) |
||||
} |
||||
|
||||
@MainActor |
||||
func requestProducts() async { |
||||
do { |
||||
|
||||
let currentPlan = AppGuard.main.currentPlan |
||||
let identifiers: [String] = [StorePlan.unlimited.rawValue] |
||||
products = try await Product.products(for: identifiers) |
||||
Logger.log("products = \(self.products.count)") |
||||
self.delegate?.productsReceived() |
||||
} catch { |
||||
self.delegate?.errorDidOccur(error: error) |
||||
Logger.error(error) |
||||
} |
||||
} |
||||
|
||||
func listenForTransactions() -> Task<Void, Error> { |
||||
return Task.detached { |
||||
//Iterate through any transactions which didn't come from a direct call to `purchase()`. |
||||
for await result in Transaction.updates { |
||||
do { |
||||
|
||||
let transaction = try await AppGuard.main.processTransactionResult(result) |
||||
|
||||
//Always finish a transaction. |
||||
await transaction.finish() |
||||
} catch { |
||||
self.delegate?.errorDidOccur(error: error) |
||||
|
||||
//StoreKit has a receipt it can read but it failed verification. Don't deliver content to the user. |
||||
print("Transaction failed verification") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
func purchase(_ product: Product) async throws -> StoreKit.Transaction? { |
||||
// Begin a purchase. |
||||
let result = try await product.purchase() |
||||
|
||||
switch result { |
||||
case .success(let verificationResult): |
||||
|
||||
let transaction = try await AppGuard.main.processTransactionResult(verificationResult) |
||||
|
||||
// Always finish a transaction. |
||||
await transaction.finish() |
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime(uptimeNanoseconds: 200000), execute: { |
||||
NotificationCenter.default.post(name: Notification.Name.StoreEventHappened, object: nil) |
||||
}) |
||||
|
||||
return transaction |
||||
case .userCancelled, .pending: |
||||
return nil |
||||
default: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue