Skip to content

Instantly share code, notes, and snippets.

@danielt1263
Last active January 10, 2017 20:56
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save danielt1263/8f59ed66ff0bb66e8d6cd261210d356e to your computer and use it in GitHub Desktop.
App Store implementation
//
// AppStore.swift
//
// Created by Daniel Tartaglia on 1/10/17.
// Copyright © 2017 Daniel Tartaglia. MIT License.
//
import Foundation
import StoreKit
enum AppStorePaymentTransactionState {
case purchasing // Transaction is being added to the server queue.
case purchased // Transaction is in queue, user has been charged.
case failed // Transaction was cancelled or failed before being added to the server queue.
case restored // Transaction was restored from user's purchase history.
case deferred // The transaction is in the queue, but its final status is pending external action.
}
protocol AppStore {
var products: [AppStoreProduct] { get }
var canMakePurchases: Bool { get }
var delegate: AppStoreDelegate? { get set }
func fetchAvailableProducts()
func restorePurchases()
func purchase(product: AppStoreProduct)
}
protocol AppStoreDelegate {
func productDescriptionsLoaded()
func restorePurchasesComplete()
func purchase(product: AppStoreProduct, state: AppStorePaymentTransactionState)
}
struct AppStoreProduct {
var price: NSDecimalNumber
var priceLocale: Locale
var localizedTitle: String
var localizedDescription: String
var productIdentifier: String
}
// MARK: implementation
private extension AppStoreProduct {
init(product: SKProduct) {
price = product.price
priceLocale = product.priceLocale
localizedTitle = product.localizedTitle
localizedDescription = product.localizedDescription
productIdentifier = product.productIdentifier
}
}
private extension AppStorePaymentTransactionState {
init(state: SKPaymentTransactionState) {
switch state {
case .purchasing:
self = .purchasing
case .purchased:
self = .purchased
case .failed:
self = .failed
case .restored:
self = .restored
case .deferred:
self = .deferred
}
}
}
class AppStoreImpl: NSObject, AppStore, SKProductsRequestDelegate, SKPaymentTransactionObserver
{
var delegate: AppStoreDelegate?
var products: [AppStoreProduct] {
return iapProducts.map { AppStoreProduct(product: $0) }
}
init(productIDs: [String]) {
self.productIDs = productIDs
}
func fetchAvailableProducts() {
let productIdentifiers = NSSet(array: productIDs)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
func restorePurchases() {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
var canMakePurchases: Bool {
return SKPaymentQueue.canMakePayments()
}
func purchase(product: AppStoreProduct) {
guard let index = iapProducts.index(where: { $0.productIdentifier == product.productIdentifier }) else { return }
let payment = SKPayment(product: iapProducts[index])
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
}
// MARK: SKProductsRequestDelegate
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
delegate?.productDescriptionsLoaded()
}
}
// MARK: SKPaymentTransactionObserver
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
if let productIndex = products.index(where: { $0.productIdentifier == transaction.payment.productIdentifier }) {
let purchaseState = AppStorePaymentTransactionState(state: transaction.transactionState)
delegate?.purchase(product: products[productIndex], state: purchaseState)
switch transaction.transactionState {
case .purchased, .restored:
SKPaymentQueue.default().finishTransaction(transaction)
default: break
}
}
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
delegate?.restorePurchasesComplete()
}
private var productsRequest = SKProductsRequest()
private var iapProducts = [SKProduct]()
private let productIDs: [String]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment