Files
2022-12-13 22:30:08 +03:00

149 lines
5.1 KiB
Swift

//
// AccountServiceIAPManager.swift
// Wallet
//
// Created by Saveliy Stavitsky on 4/12/21.
// Copyright © 2021 AM. All rights reserved.
//
import Foundation
import StoreKit
extension AccountOnboarding.Service {
class IAP: NSObject {
private let newAccountProducatIAPID = "life.malinka.wallet.newaccount"
var products: [SKProduct] = []
var transactions = SKPaymentQueue.default().transactions
var onReceiveProductsHandler: ((Result<[SKProduct], IAPManagerError>) -> Void)?
var onBuyProductHandler: ((Result<SKPaymentTransaction, Error>) -> Void)?
static let shared = IAP()
private override init() {
super.init()
}
func getProducts(withHandler productsReceiveHandler: ((_ result: Result<[SKProduct], IAPManagerError>) -> Void)? = nil) {
onReceiveProductsHandler = productsReceiveHandler
let request = SKProductsRequest(productIdentifiers: Set([newAccountProducatIAPID]))
request.delegate = self
request.start()
}
enum IAPManagerError: Error {
case noProductIDsFound
case noProductsFound
case paymentWasCancelled
case productRequestFailed
}
func canMakePayments() -> Bool {
return SKPaymentQueue.canMakePayments()
}
func startObserving() {
SKPaymentQueue.default().add(self)
}
func stopObserving() {
SKPaymentQueue.default().remove(self)
}
func buy(product: SKProduct, withHandler handler: @escaping ((_ result: Result<SKPaymentTransaction, Error>) -> Void)) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
onBuyProductHandler = handler
}
func getAppStoreReceipt() -> String? {
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
print(receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
return receiptString
} catch {
print("Couldn't read receipt data with error: " + error.localizedDescription)
return nil
}
}
return nil
}
func finishTransaction(transaction: SKPaymentTransaction) {
SKPaymentQueue.default().finishTransaction(transaction)
}
}
}
extension AccountOnboarding.Service.IAP.IAPManagerError: LocalizedError {
var errorDescription: String? {
switch self {
case .noProductIDsFound: return "No In-App Purchase product identifiers were found."
case .noProductsFound: return "No In-App Purchases were found."
case .productRequestFailed: return "Unable to fetch available In-App Purchase products at the moment."
case .paymentWasCancelled: return "In-App Purchase process was cancelled."
}
}
}
extension AccountOnboarding.Service.IAP: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
products = response.products
if products.count > 0 {
onReceiveProductsHandler?(.success(products))
} else {
onReceiveProductsHandler?(.failure(.noProductsFound))
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
onReceiveProductsHandler?(.failure(.productRequestFailed))
}
func requestDidFinish(_ request: SKRequest) {
}
}
extension AccountOnboarding.Service.IAP: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
transactions.forEach { (transaction) in
switch transaction.transactionState {
case .purchased:
onBuyProductHandler?(.success(transaction))
// SKPaymentQueue.default().finishTransaction(transaction)
case .restored:
break
case .failed:
if let error = transaction.error as? SKError {
if error.code != .paymentCancelled {
onBuyProductHandler?(.failure(error))
} else {
onBuyProductHandler?(.failure(IAPManagerError.paymentWasCancelled))
}
print("IAP Error:", error.localizedDescription)
}
SKPaymentQueue.default().finishTransaction(transaction)
case .deferred, .purchasing: break
@unknown default: break
}
}
}
}
extension SKProduct {
public func localizedPrice() -> String? {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = self.priceLocale
return formatter.string(from: self.price)
}
}