mirror of
https://github.com/readest/readest.git
synced 2026-04-29 12:00:49 +00:00
feat: add IAP in native bridge plugin for iOS (#1673)
This commit is contained in:
parent
beaf034035
commit
f3e9983742
16 changed files with 718 additions and 2 deletions
|
|
@ -0,0 +1,121 @@
|
|||
import StoreKit
|
||||
import os
|
||||
|
||||
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "StoreKitManager")
|
||||
|
||||
class StoreKitManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
|
||||
static let shared = StoreKitManager()
|
||||
|
||||
private var productsRequest: SKProductsRequest?
|
||||
private var productResponseHandler: (([SKProduct]) -> Void)?
|
||||
private var purchaseHandler: ((Result<SKPaymentTransaction, Error>) -> Void)?
|
||||
private var restoreHandler: (([SKPaymentTransaction]) -> Void)?
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
func initialize() {
|
||||
SKPaymentQueue.default().add(self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
SKPaymentQueue.default().remove(self)
|
||||
}
|
||||
|
||||
func fetchProducts(productIds: [String], completion: @escaping ([SKProduct]) -> Void) {
|
||||
let ids = Set(productIds)
|
||||
productsRequest = SKProductsRequest(productIdentifiers: ids)
|
||||
productsRequest?.delegate = self
|
||||
productResponseHandler = completion
|
||||
productsRequest?.start()
|
||||
}
|
||||
|
||||
func purchase(
|
||||
product: SKProduct, completion: @escaping (Result<SKPaymentTransaction, Error>) -> Void
|
||||
) {
|
||||
guard SKPaymentQueue.canMakePayments() else {
|
||||
completion(
|
||||
.failure(
|
||||
NSError(
|
||||
domain: "iap", code: 0, userInfo: [NSLocalizedDescriptionKey: "Purchases disabled."])))
|
||||
return
|
||||
}
|
||||
purchaseHandler = completion
|
||||
let payment = SKPayment(product: product)
|
||||
SKPaymentQueue.default().add(payment)
|
||||
}
|
||||
|
||||
func restorePurchases(completion: @escaping ([SKPaymentTransaction]) -> Void) {
|
||||
restoreHandler = completion
|
||||
SKPaymentQueue.default().restoreCompletedTransactions()
|
||||
}
|
||||
|
||||
// MARK: - SKProductsRequestDelegate
|
||||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.productResponseHandler?(response.products)
|
||||
self?.productResponseHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
func request(_ request: SKRequest, didFailWithError error: Error) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
logger.error("Products request failed: \(error.localizedDescription)")
|
||||
self?.productResponseHandler?([])
|
||||
self?.productResponseHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SKPaymentTransactionObserver
|
||||
func paymentQueue(
|
||||
_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]
|
||||
) {
|
||||
for transaction in transactions {
|
||||
switch transaction.transactionState {
|
||||
case .purchased:
|
||||
SKPaymentQueue.default().finishTransaction(transaction)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.purchaseHandler?(.success(transaction))
|
||||
self?.purchaseHandler = nil
|
||||
}
|
||||
case .failed:
|
||||
SKPaymentQueue.default().finishTransaction(transaction)
|
||||
let error =
|
||||
transaction.error
|
||||
?? NSError(
|
||||
domain: "iap", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown purchase error"]
|
||||
)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.purchaseHandler?(.failure(error))
|
||||
self?.purchaseHandler = nil
|
||||
}
|
||||
case .restored:
|
||||
SKPaymentQueue.default().finishTransaction(transaction)
|
||||
case .deferred, .purchasing:
|
||||
// Handle these states if needed
|
||||
break
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
|
||||
let restored = queue.transactions.filter { $0.transactionState == .restored }
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.restoreHandler?(restored)
|
||||
self?.restoreHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
func paymentQueue(
|
||||
_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error
|
||||
) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
logger.error("Restore purchases failed: \(error.localizedDescription)")
|
||||
self?.restoreHandler?([])
|
||||
self?.restoreHandler = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue