Skip to content

Instantly share code, notes, and snippets.

@schevgeny
Created March 13, 2024 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schevgeny/3579a56ef474992c744b382cb7510e21 to your computer and use it in GitHub Desktop.
Save schevgeny/3579a56ef474992c744b382cb7510e21 to your computer and use it in GitHub Desktop.
SubscriptionManager.swift
import StoreKit
import SwiftyStoreKit
typealias PurchaseHandler = (_ transactionId: String?, _ success: Bool, _ error: Error?) -> ()
final class SubscriptionManager: ObservableObject {
static let shared = SubscriptionManager()
@Published var hasActiveSubscription = false
private var products: [SKProduct] = []
private var purchasedProductIDs = Set<String>()
private var subscriptionsIds: Set<String> {
return Set([
"\(bundleID).weekly_3",
"\(bundleID).weekly_4",
"\(bundleID).weekly7",
"\(bundleID).weekly_9",
"\(bundleID).monthly_7",
"\(bundleID).monthly_9",
"\(bundleID).monthly_14",
"\(bundleID).monthly_19",
"\(bundleID).yearly_29",
"\(bundleID).yearly_39",
"\(bundleID).yearly_49",
"\(bundleID).yearly_59",
"\(bundleID).yearly_89",
"\(bundleID).yearly_119",
"\(bundleID).lifetime",
])
}
private var bundleID: String {
return Bundle.main.bundleIdentifier ?? "error"
}
init() {
loadProducts()
updatePurchasedProducts()
}
public func getProductById(_ productId: String) -> SKProduct? {
return products.first(where: { $0.productIdentifier == productId })
}
public func purchase(productId: String, completion: @escaping PurchaseHandler) {
guard let product = products.first(where: { $0.productIdentifier == productId }) else {
completion(nil, false, nil)
return
}
SwiftyStoreKit.purchaseProduct(productId, quantity: 1, atomically: true) { result in
switch result {
case .success(let purchase):
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
self.updatePurchasedProducts()
completion(purchase.transaction.transactionIdentifier, true, nil)
case .error(let error):
completion(nil, false, error)
}
}
}
public func restorePurchases() {
Task.init {
((try? await AppStore.sync()) != nil)
}
}
private func loadProducts() {
SwiftyStoreKit.retrieveProductsInfo(subscriptionsIds) { result in
self.products = Array(result.retrievedProducts ) // Convert Set to Array
}
}
private func updatePurchasedProducts() {
guard let receiptURL = Bundle.main.appStoreReceiptURL,
let receiptData = try? Data(contentsOf: receiptURL) else {
print("Failed to retrieve receipt data.")
return
}
do {
let json = try JSONSerialization.jsonObject(with: receiptData, options: [])
guard let receiptInfo = json as? [String: Any],
let receiptEntries = receiptInfo["receipt"] as? [[String: Any]] else {
print("Failed to extract receipt information.")
return
}
var purchasedProductIDs = Set<String>()
for entry in receiptEntries {
if let productID = entry["product_id"] as? String {
purchasedProductIDs.insert(productID)
}
}
self.purchasedProductIDs = purchasedProductIDs
self.hasActiveSubscription = !purchasedProductIDs.isEmpty
} catch {
print("Error parsing receipt: \(error)")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment