Created
August 31, 2016 01:03
-
-
Save brien-crean/3140d3b6463649f3c20f0950d0c01d21 to your computer and use it in GitHub Desktop.
In App Purchases iOS - Swift 2
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
import Foundation; | |
import StoreKit; | |
struct ProductList { | |
static let twoWeekTrial : String = "twoweektrial" | |
static let monthlySub : String = "monthlytrial" | |
static let products = [twoWeekTrial, monthlySub] | |
} | |
class StoreManager: NSObject { | |
var loadedProducts: Dictionary<String, SKProduct> = [:] | |
var purchaseCallbackHolder: RCTResponseSenderBlock? = nil | |
var productsCallbackHolder: RCTResponseSenderBlock? = nil | |
var restoreCallbackHolder: RCTResponseSenderBlock? = nil | |
override init() { | |
super.init() | |
SKPaymentQueue.defaultQueue().addTransactionObserver(self) | |
} | |
// NOTE: Leaving this out caused all sorts of weirdness for me | |
deinit { | |
if SKPaymentQueue.canMakePayments() { | |
SKPaymentQueue.defaultQueue().removeTransactionObserver(self) | |
} | |
} | |
func getProductList(callback: RCTResponseSenderBlock){ | |
if SKPaymentQueue.canMakePayments() { | |
// products from static struct | |
let products = NSSet(array: ProductList.products); | |
// When request completes, calls the SKProductsRequestDelegate | |
let request = SKProductsRequest(productIdentifiers: products as! Set<String>); | |
productsCallbackHolder = callback | |
request.delegate = self; | |
request.start(); | |
} | |
} | |
func purchaseProduct(productIdentifier: String, callback: RCTResponseSenderBlock) { | |
let product = loadedProducts[productIdentifier as String]! | |
let payment = SKPayment(product: product) | |
// add callback to holder | |
purchaseCallbackHolder = callback | |
// Triggers SKPaymentTransactionObserver | |
SKPaymentQueue.defaultQueue().addPayment(payment) | |
} | |
func restorePurchases(callback: RCTResponseSenderBlock){ | |
restoreCallbackHolder = callback | |
SKPaymentQueue.defaultQueue().restoreCompletedTransactions() | |
} | |
func validatePurchases(callback: RCTResponseSenderBlock) -> Void { | |
let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL | |
let receipt: NSData = NSData(contentsOfURL:receiptUrl!)! | |
let receiptdata: NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) | |
// Pass Base64 encoded string back to JS | |
// NOTE: The Javascript handles sending the receipt to Apple (easier to handle JSON) | |
callback([receiptdata]) | |
} | |
func getReceipt() -> NSString { | |
let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL | |
let receipt: NSData = NSData(contentsOfURL:receiptUrl!)! | |
let receiptdata: NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) | |
return receiptdata; | |
} | |
func updateWithProducts(products: [SKProduct]) { | |
var productIdentifiers: Dictionary<String, NSNumber> = [:] | |
for product in products { | |
loadedProducts[product.productIdentifier] = product | |
productIdentifiers[product.productIdentifier] = product.price | |
print(product.productIdentifier) | |
} | |
productsCallbackHolder?([productIdentifiers]) | |
productsCallbackHolder = nil | |
} | |
} | |
extension StoreManager: SKProductsRequestDelegate { | |
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) { | |
// products retrieved from App store | |
let appProducts = response.products | |
if appProducts.count != 0 { | |
for product in appProducts{ | |
print(product.productIdentifier) | |
} | |
print(appProducts) | |
updateWithProducts(appProducts) | |
} | |
else { | |
print("no products received from store") | |
} | |
} | |
} | |
extension StoreManager: SKPaymentTransactionObserver { | |
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { | |
print("Received Payment Transaction Response from Apple"); | |
for transaction:AnyObject in transactions { | |
// check object is a transaction first | |
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{ | |
switch trans.transactionState { | |
case .Purchased: | |
print("Product Purchased"); | |
// get receipt and back to JS for verification check | |
let receipt = getReceipt() | |
purchaseCallbackHolder?([receipt]) | |
purchaseCallbackHolder = nil | |
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) | |
break; | |
case .Failed: | |
print("Purchased Failed"); | |
purchaseCallbackHolder?([]) | |
purchaseCallbackHolder = nil | |
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) | |
break; | |
case .Restored: | |
print("Purchases Restored"); | |
restoreCallbackHolder?([]) | |
restoreCallbackHolder = nil | |
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) | |
default: | |
break; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment