Skip to content

Instantly share code, notes, and snippets.

@u5-03
Created June 21, 2021 00:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save u5-03/23fe96e2983474f27a285eefafff7751 to your computer and use it in GitHub Desktop.
Save u5-03/23fe96e2983474f27a285eefafff7751 to your computer and use it in GitHub Desktop.
StoreKitUtil
//
// 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