Created
June 21, 2021 00:48
-
-
Save u5-03/23fe96e2983474f27a285eefafff7751 to your computer and use it in GitHub Desktop.
StoreKitUtil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created on 2020/05/16 | |
// Copyright © 2020年, yugo.sugiyama. All rights reserved. | |
// | |
import Foundation | |
import RxSwift | |
import RxCocoa | |
import StoreKit | |
import SwiftyStoreKit | |
enum StorePurchaseRestoreStatus { | |
case success | |
case nothingRestore | |
} | |
enum StoreKitError: Error { | |
case invalidProductId(productId: String) | |
case clientInvalid | |
case paymentCancelled | |
case paymentInvalid | |
case paymentNotAllowed | |
case storeProductNotAvailable | |
case cloudServicePermissionDenied | |
case cloudServiceNetworkConnectionFailed | |
case cloudServiceRevoked | |
case restoreFailedPurchase | |
case unknownError(message: String? = nil) | |
} | |
extension StoreKitError: ErrorProtocol { | |
var message: String { | |
switch self { | |
case .invalidProductId(let productId): return R.string.localizable.storeKitErrorInvalidProductId(productId) | |
case .clientInvalid: return R.string.localizable.storeKitErrorClientInvalid() | |
case .paymentCancelled: return R.string.localizable.storeKitErrorPaymentCancelled() | |
case .paymentInvalid: return R.string.localizable.storeKitErrorPaymentInvalid() | |
case .paymentNotAllowed: return R.string.localizable.storeKitErrorPaymentNotAllowed() | |
case .storeProductNotAvailable: return R.string.localizable.storeKitErrorStoreProductNotAvailable() | |
case .cloudServicePermissionDenied: return R.string.localizable.storeKitErrorCloudServicePermissionDenied() | |
case .cloudServiceNetworkConnectionFailed: return R.string.localizable.storeKitErrorCloudServiceNetworkConnectionFailed() | |
case .cloudServiceRevoked: return R.string.localizable.storeKitErrorCloudServiceRevoked() | |
case .restoreFailedPurchase: return R.string.localizable.storeKitErrorRestoreFailedPurchase() | |
case .unknownError(let message): | |
if let message = message { | |
return message | |
} else { | |
return R.string.localizable.storeKitErrorUnknownError() | |
} | |
} | |
} | |
} | |
final class StoreKitUtil { | |
static func registerTransaction() { | |
SwiftyStoreKit.completeTransactions(atomically: true) { purchases in | |
for purchase in purchases { | |
switch purchase.transaction.transactionState { | |
case .purchased, .restored: | |
if purchase.needsFinishTransaction { | |
SwiftyStoreKit.finishTransaction(purchase.transaction) | |
} | |
// Apple Review rejected below: does not include a "Restore Purchase" feature | |
// UserDefaults.standard.setAdStatus(shouldShow: false) | |
case .failed, .purchasing, .deferred: | |
break | |
@unknown default: | |
break | |
} | |
} | |
} | |
} | |
static func retrieveProductInfo(productIdList: Set<String>) -> Single<SKProduct> { | |
Single<SKProduct>.create { single -> Disposable in | |
SwiftyStoreKit.retrieveProductsInfo(productIdList) { result in | |
if let product = result.retrievedProducts.first { | |
single(.success(product)) | |
} else if let invalidProductId = result.invalidProductIDs.first { | |
single(.error(StoreKitError.invalidProductId(productId: invalidProductId))) | |
} else if let error = result.error { | |
single(.error(error)) | |
} else { | |
single(.error(StoreKitError.unknownError(message: nil))) | |
} | |
} | |
return Disposables.create() | |
} | |
} | |
static func purchaseProduct(productId: String, quantity: Int, automatically: Bool) -> Single<Void> { | |
Single<Void>.create { single -> Disposable in | |
SwiftyStoreKit.purchaseProduct(productId, quantity: quantity, atomically: automatically) { result in | |
switch result { | |
case .success: | |
single(.success(())) | |
case .error(let error): | |
switch error.code { | |
case .clientInvalid: single(.error(StoreKitError.clientInvalid)) | |
case .paymentCancelled: single(.error(StoreKitError.paymentCancelled)) | |
case .paymentInvalid: single(.error(StoreKitError.paymentInvalid)) | |
case .paymentNotAllowed: single(.error(StoreKitError.paymentNotAllowed)) | |
case .storeProductNotAvailable: single(.error(StoreKitError.storeProductNotAvailable)) | |
case .cloudServicePermissionDenied: single(.error(StoreKitError.cloudServicePermissionDenied)) | |
case .cloudServiceNetworkConnectionFailed: single(.error(StoreKitError.cloudServiceNetworkConnectionFailed)) | |
case .cloudServiceRevoked: single(.error(StoreKitError.cloudServiceRevoked)) | |
default: single(.error(StoreKitError.unknownError(message: nil))) | |
} | |
} | |
} | |
return Disposables.create() | |
} | |
} | |
static func restorePurchases(atomically: Bool) -> Single<StorePurchaseRestoreStatus> { | |
Single<StorePurchaseRestoreStatus>.create { single -> Disposable in | |
SwiftyStoreKit.restorePurchases(atomically: atomically) { results in | |
if !results.restoreFailedPurchases.isEmpty { | |
single(.error(StoreKitError.restoreFailedPurchase)) | |
} else if !results.restoredPurchases.isEmpty { | |
single(.success(.success)) | |
} else { | |
single(.success(.nothingRestore)) | |
} | |
} | |
return Disposables.create() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment