Skip to content

Instantly share code, notes, and snippets.

@NathanJang
Last active March 31, 2017 20:13
Show Gist options
  • Save NathanJang/429d4672a2001621c8dacce0a5ef0835 to your computer and use it in GitHub Desktop.
Save NathanJang/429d4672a2001621c8dacce0a5ef0835 to your computer and use it in GitHub Desktop.
// A simplified version of my view controller implementation.
// Assume that the user hasn't purchased anything yet, and that I will persist the transaction properly to user defaults.
import UIKit
import StoreKit
/// A view controller for the settings.
class SettingsTableViewController: UITableViewController {
/// The widget's IAP product, which will exist after we query the app store.
var widgetProduct: SKProduct?
override func viewDidLoad() {
super.viewDidLoad()
guard SKPaymentQueue.canMakePayments() else {
return
}
let request = SKProductsRequest(productIdentifiers: [MY_PRODUCT_IDENTIFIER])
request.delegate = self
request.start()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
SKPaymentQueue.default().remove(self)
}
// ...
/// Prompts the user to purchase the widget if `widgetProduct` is not nil, i.e., if it is available from the app store.
/// This is called when the user taps a button in the UI somewhere.
func buyWidgetIfAvailable() {
guard let widgetProduct = widgetProduct else { return }
let payment = SKPayment(product: widgetProduct)
SKPaymentQueue.default().add(payment)
}
}
extension SettingsTableViewController: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
// Show list of available purchases
for product in response.products {
if product.productIdentifier == MY_PRODUCT_IDENTIFIER {
self.widgetProduct = product
}
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
// Alert the user
}
/// What to do once the widget is purchased.
func didPurchaseWidget() {
// Persist the transaction to user defaults and alert the user.
}
}
extension SettingsTableViewController: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
handleTransaction(transaction, withQueue: queue)
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
for transaction in queue.transactions {
if transaction.transactionState == .restored {
didPurchaseWidget()
queue.finishTransaction(transaction)
}
}
if /* check in user defaults if widget is not purchased */ {
// Alert the user that there is no previous transaction to restore
}
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
// Alert user
}
/// What to do once we receive a transaction.
/// - Parameter transaction: The StoreKit transaction.
/// - Parameter queue: The StoreKit payment queue.
func handleTransaction(_ transaction: SKPaymentTransaction, withQueue queue: SKPaymentQueue) {
switch transaction.transactionState {
case .purchased:
if transaction.payment.productIdentifier == MY_PRODUCT_IDENTIFIER {
didPurchaseWidget()
queue.finishTransaction(transaction)
}
case .failed:
// Alert the user
// Should I be running finishTransaction?
// queue.finishTransaction(transaction)
// Is this case redundant?
case .restored:
if transaction.payment.productIdentifier == MY_PRODUCT_IDENTIFIER {
didPurchaseWidget()
queue.finishTransaction(transaction)
}
default:
break
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment