Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,121 @@
fileprivate struct BillingProduct: IBillingProduct {
var productId: String {
return product.productIdentifier
}
var localizedName: String {
return product.localizedTitle
}
var price: NSDecimalNumber {
return product.price
}
var priceLocale: Locale {
return product.priceLocale
}
let product: SKProduct
init(_ product: SKProduct) {
self.product = product
}
}
final class InAppBilling: NSObject, IInAppBilling {
private var productsCompletion: ProductsCompletion?
private var paymentCompletion: PaymentCompletion?
private var productRequest: SKProductsRequest?
private var billingProduct: BillingProduct?
private var pendingTransaction: SKPaymentTransaction?
override init() {
super.init()
SKPaymentQueue.default().add(self)
}
deinit {
productRequest?.cancel()
productRequest?.delegate = nil
SKPaymentQueue.default().remove(self)
}
func requestProducts(_ productIds: Set<String>, completion: @escaping ProductsCompletion) {
productsCompletion = completion
productRequest = SKProductsRequest(productIdentifiers: productIds)
productRequest!.delegate = self
productRequest!.start()
}
func makePayment(_ product: IBillingProduct, completion: @escaping PaymentCompletion) {
guard let billingProduct = product as? BillingProduct else {
assert(false, "Wrong product type")
return
}
paymentCompletion = completion
self.billingProduct = billingProduct
SKPaymentQueue.default().add(SKPayment(product: billingProduct.product))
}
func finishTransaction() {
guard let transaction = pendingTransaction else {
assert(false, "You must call makePayment() first")
return
}
SKPaymentQueue.default().finishTransaction(transaction)
billingProduct = nil
pendingTransaction = nil
}
}
extension InAppBilling: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async { [weak self] in
let products = response.products.map { BillingProduct($0) }
self?.productsCompletion?(products, nil)
self?.productsCompletion = nil
self?.productRequest = nil
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
DispatchQueue.main.async { [weak self] in
self?.productsCompletion?(nil, error)
self?.productsCompletion = nil
self?.productRequest = nil
}
}
}
extension InAppBilling: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
guard let productId = billingProduct?.productId else { return }
transactions.forEach {
if ($0.payment.productIdentifier != productId) { return }
self.pendingTransaction = $0
switch $0.transactionState {
case .purchasing:
break
case .purchased:
paymentCompletion?(.success, nil)
break
case .failed:
if ($0.error?._code == SKError.paymentCancelled.rawValue) {
paymentCompletion?(.userCancelled, $0.error)
} else {
paymentCompletion?(.failed, $0.error)
}
break
case .restored:
break
case .deferred:
paymentCompletion?(.deferred, nil)
break
}
}
}
}