Last active
March 31, 2017 20:13
-
-
Save NathanJang/429d4672a2001621c8dacce0a5ef0835 to your computer and use it in GitHub Desktop.
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
// 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