我在我的应用程序中使用以下帮助程序进行购买。当我调用时IAPHelper.default.initialize {_ in }
,就会调用 productsRequest 方法。
但是当我想进行购买并调用方法时
IAPHelper.default.purchaseProduct (productId: "month_subscription") {[weak self] result in
print ("results =", result) }
SKPaymentQueue.default().add(self)
进行了购买,但在方法 purchaseProduct() 中添加的 updatedTransactions 方法没有被调用(在 SKPaymentTransactionObserver
中)
我究竟做错了什么?
enum IAPHelperError: Error {
case purchaseInProgress
case productNotFound
case unknown
}
typealias RequestProductsResult = Result<[SKProduct], Error>
typealias PurchaseProductResult = Result<Bool, Error>
typealias RequestProductsCompletion = (RequestProductsResult) -> Void
typealias PurchaseProductCompletion = (PurchaseProductResult) -> Void
class IAPHelperTest: NSObject {
static let `default` = IAPHelperTest()
//MARK: - product identificators
private let productIdentifiers = Set(["month_subscription"])
var products: [String: SKProduct]?
private var productRequest: SKProductsRequest?
private var productPurchaseCallback: ((PurchaseProductResult) -> Void)?
func initialize(completion: @escaping RequestProductsCompletion) {
requestProducts(completion: completion)
}
private var productsRequestCallbacks = [RequestProductsCompletion]()
private func requestProducts(completion: @escaping RequestProductsCompletion) {
guard productsRequestCallbacks.isEmpty else {
productsRequestCallbacks.append(completion)
return
}
productsRequestCallbacks.append(completion)
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
productRequest.delegate = self
productRequest.start()
self.productRequest = productRequest
}
//запрос продуктов по идентификаторам пришедшим с сервера
private func requestProducts(productIdentifiers: Set<String>, completion: @escaping RequestProductsCompletion) {
guard productsRequestCallbacks.isEmpty else {
productsRequestCallbacks.append(completion)
return
}
productsRequestCallbacks.append(completion)
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
productRequest.delegate = self
productRequest.start()
self.productRequest = productRequest
}
//Purchase Product
public func purchaseProduct(productId: String, completion: @escaping (PurchaseProductResult) -> Void) {
guard productPurchaseCallback == nil else {
completion(.failure(IAPHelperError.purchaseInProgress))
return
}
guard let product = products?[productId] else {
completion(.failure(IAPHelperError.productNotFound))
return
}
productPurchaseCallback = completion
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
public func restorePurchases(completion: @escaping (PurchaseProductResult) -> Void) {
guard productPurchaseCallback == nil else {
completion(.failure(IAPHelperError.purchaseInProgress))
return
}
productPurchaseCallback = completion
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
//MARK: - SKProductsRequestDelegate
extension IAPHelperTest: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
for invalidIdentifier in response.invalidProductIdentifiers {
print("invalidIdentifier =", invalidIdentifier)
}
guard !response.products.isEmpty else {
productsRequestCallbacks.forEach { $0(.success(response.products)) }
productsRequestCallbacks.removeAll()
return
}
var products = [String: SKProduct]()
for skProduct in response.products {
products[skProduct.productIdentifier] = skProduct
}
self.products = products
productsRequestCallbacks.forEach { $0(.success(response.products)) }
productsRequestCallbacks.removeAll()
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Failed to load products with error:\n \(error)")
productsRequestCallbacks.forEach { $0(.failure(error)) }
productsRequestCallbacks.removeAll()
}
}
//MARK: - SKPaymentTransactionObserver
extension IAPHelperTest: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased, .restored:
if finishTransaction(transaction) {
SKPaymentQueue.default().finishTransaction(transaction)
productPurchaseCallback?(.success(true))
} else {
productPurchaseCallback?(.failure(IAPHelperError.unknown))
}
break
case .failed:
productPurchaseCallback?(.failure(transaction.error ?? IAPHelperError.unknown))
SKPaymentQueue.default().finishTransaction(transaction)
break
default:
break
}
}
productPurchaseCallback = nil
}
func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) {
}
}
extension IAPHelperTest {
private func finishTransaction(_ transaction: SKPaymentTransaction) -> Bool {
let productId = transaction.payment.productIdentifier
print("Product \(productId) successfully purchased")
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
print("receiptData =", receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
print("receiptString = ",receiptString)
// Read receiptData
}
catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
return true
}
}