149 lines
5.1 KiB
Swift
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)
|
|
}
|
|
}
|