Various improvements

This commit is contained in:
Ilya Laktyushin
2022-06-11 09:10:01 +04:00
parent 4251ee2c1b
commit fbccdd47df
22 changed files with 992 additions and 217 deletions

View File

@@ -30,6 +30,8 @@ public final class InAppPurchaseManager: NSObject {
case cancelled
case network
case notAllowed
case cantMakePayments
case assignFailed
}
public enum RestoreState {
@@ -51,6 +53,7 @@ public final class InAppPurchaseManager: NSObject {
case restored(transactionId: String?)
case purchasing
case failed(error: SKError?)
case assignFailed
case deferred
}
@@ -63,7 +66,7 @@ public final class InAppPurchaseManager: NSObject {
private let stateQueue = Queue()
private var paymentContexts: [String: PaymentTransactionContext] = [:]
private var onRestoreCompletion: ((RestoreState) -> Void)?
private let disposableSet = DisposableDict<String>()
@@ -82,6 +85,10 @@ public final class InAppPurchaseManager: NSObject {
SKPaymentQueue.default().remove(self)
}
var canMakePayments: Bool {
return SKPaymentQueue.canMakePayments()
}
private func requestProducts() {
guard !self.premiumProductId.isEmpty else {
return
@@ -119,10 +126,16 @@ public final class InAppPurchaseManager: NSObject {
}
}
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> {
Logger.shared.log("InAppPurchaseManager", "Buying product: \(product.skProduct.productIdentifier), price \(product.price)")
public func buyProduct(_ product: Product) -> Signal<PurchaseState, PurchaseError> {
if !self.canMakePayments {
return .fail(.cantMakePayments)
}
let accountPeerId = "\(self.engine.account.peerId.toInt64())"
let payment = SKPayment(product: product.skProduct)
Logger.shared.log("InAppPurchaseManager", "Buying: account \(accountPeerId), product \(product.skProduct.productIdentifier), price \(product.price)")
let payment = SKMutablePayment(product: product.skProduct)
payment.applicationUsername = accountPeerId
SKPaymentQueue.default().add(payment)
let productIdentifier = payment.productIdentifier
@@ -156,6 +169,8 @@ public final class InAppPurchaseManager: NSObject {
} else {
subscriber.putError(.generic)
}
case .assignFailed:
subscriber.putError(.assignFailed)
case .deferred, .purchasing:
break
}
@@ -205,39 +220,48 @@ private func getReceiptData() -> Data? {
extension InAppPurchaseManager: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
let accountPeerId = "\(self.engine.account.peerId.toInt64())"
if let applicationUsername = transaction.payment.applicationUsername, applicationUsername != accountPeerId {
continue
}
let productIdentifier = transaction.payment.productIdentifier
self.stateQueue.async {
let transactionState: TransactionState?
switch transaction.transactionState {
case .purchased:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased")
let transactionIdentifier = transaction.transactionIdentifier
transactionState = .purchased(transactionId: transactionIdentifier)
if let transactionIdentifier = transactionIdentifier {
self.disposableSet.set(
self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { _ in
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction")
self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { [weak self] _ in
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction")
queue.finishTransaction(transaction)
if let strongSelf = self, let context = strongSelf.paymentContexts[productIdentifier] {
context.subscriber(.assignFailed)
}
}, completed: {
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction")
queue.finishTransaction(transaction)
}),
forKey: transactionIdentifier
)
}
case .restored:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring")
let transactionIdentifier = transaction.transactionIdentifier
transactionState = .restored(transactionId: transactionIdentifier)
case .failed:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed \((transaction.error as? SKError)?.localizedDescription ?? "")")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") failed \((transaction.error as? SKError)?.localizedDescription ?? "")")
transactionState = .failed(error: transaction.error as? SKError)
queue.finishTransaction(transaction)
case .purchasing:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") purchasing")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") purchasing")
transactionState = .purchasing
case .deferred:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") deferred")
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") deferred")
transactionState = .deferred
default:
transactionState = nil