Skip to content

Instantly share code, notes, and snippets.

@speaktoalvin
Last active April 29, 2021 04:07
Show Gist options
  • Save speaktoalvin/7c61bab7a401e22ee8c5 to your computer and use it in GitHub Desktop.
Save speaktoalvin/7c61bab7a401e22ee8c5 to your computer and use it in GitHub Desktop.
In App Purchase in Swift, with Receipt Validation
import UIKit
import StoreKit
//MARK: SKProductsRequestDelegate
extension IAPHelpers : SKProductsRequestDelegate
{
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse)
{
if response.products.count > 0
{
let validProduct : SKProduct = response.products[0]
switch validProduct.productIdentifier {
case PRODUCT_IDENTIFIERS.k_10_WORDS_PRODUCT_IDENTIFIER.rawValue :
self.buyProduct(validProduct)
case PRODUCT_IDENTIFIERS.k_20_WORDS_PRODUCT_IDENTIFIER.rawValue :
self.buyProduct(validProduct)
case PRODUCT_IDENTIFIERS.k_ALL_WORDS_PRODUCT_IDENTIFIER.rawValue :
self.buyProduct(validProduct)
default :
self.alertThis("Sorry", message: "No products recieved from server", current: self.currentViewController)
}
} else {
self.alertThis("Sorry", message: "Can't make payments, Please check in settings.", current: self.currentViewController)
}
}
}
extension IAPHelpers : SKRequestDelegate
{
func requestDidFinish(request: SKRequest)
{
}
func request(request: SKRequest, didFailWithError error: NSError)
{
self.alertThis("Sorry", message: "\(error.localizedDescription)", current: self.currentViewController)
}
}
//MARK: SKPaymentTransactionObserver
extension IAPHelpers : SKPaymentTransactionObserver
{
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
{
self.handlingTransactions(transactions)
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue)
{
if queue.transactions.count == 0
{
self.alertThis("Sorry", message: "You didnt make any purchase to restiore, Please do a purchase first.", current: self.currentViewController)
}
else
{
self.handlingTransactions(queue.transactions)
}
}
func paymentQueue(queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: NSError)
{
self.alertThis("Sorry", message: "\(error.localizedDescription)", current: self.currentViewController)
}
}
enum PRODUCT_IDENTIFIERS : String
{
//MARK: Product ID's
case k_10_WORDS_PRODUCT_IDENTIFIER = "YOUR_PRODUCT_IDENTIFIER_10"
case k_20_WORDS_PRODUCT_IDENTIFIER = "YOUR_PRODUCT_IDENTIFIER_20"
case k_ALL_WORDS_PRODUCT_IDENTIFIER = "YOUR_PRODUCT_IDENTIFIER_ALL"
case k_RESTORE_WORDS_PRODUCT_IDENTIFIER = "YOUR_PRODUCT_IDENTIFIER_RESTOREE"
}
enum USER_DEFAULTS_IDENTIFIERS : String
{
case TEN_WORDS_PRODUCT_IDENTIFIER = "10_WORDS_IDENTIFIER"
case TWENTY_WORDS_PRODUCT_IDENTIFIER = "20_WORDS_IDENTIFIER"
case ALL_WORDS_PRODUCT_IDENTIFIER = "ALL_WORDS_IDENTIFIER"
}
enum ReceiptURL : String
{
case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
case production = "https://buy.itunes.apple.com/verifyReceipt"
case myServer = "your server"
}
protocol StoreRequestIAPPorotocol
{
func transactionCompletedForRequest(PRODUCT_ID : String)
}
class IAPHelpers: NSObject {
//MARK: Variables
var delegate : StoreRequestIAPPorotocol!
var currentViewController : UIViewController!
//MARK: - Creating sharedInstance
class var sharedInstance: IAPHelpers {
struct Static {
static var sharedInstance: IAPHelpers?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.sharedInstance = IAPHelpers()
}
return Static.sharedInstance!
}
//MARK: Product Request
func productRquestStarted(productReferenceName : String)
{
if (SKPaymentQueue.canMakePayments()) {
if productReferenceName == PRODUCT_IDENTIFIERS.k_RESTORE_WORDS_PRODUCT_IDENTIFIER.rawValue
{
self.restorePurchases()
}
else
{
let productID : Set<String> = [productReferenceName]
let productsRequest : SKProductsRequest = SKProductsRequest(productIdentifiers: productID)
productsRequest.delegate = self
productsRequest.start()
}
} else {
// PRESENT A USER FOR UI about not being able to make payments.
}
}
//MARK: Buy Product - Payment Section
func buyProduct(product : SKProduct)
{
let payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
//MARK: Restore Transaction
func restoreTransaction(transaction : SKPaymentTransaction)
{
self.deliverProduct(transaction.payment.productIdentifier)
}
//MARK: Restore Purchases
func restorePurchases()
{
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
//MARK: - Showing UIAlertView
func alertThis(title : String, message : String, current : UIViewController)
{
let alertView : UIAlertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alertView.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: { _ in
}))
current.presentViewController(alertView, animated: true, completion: nil)
}
//MARK: Transaction Observer Handler
func handlingTransactions(transactions : [AnyObject])
{
for transaction in transactions {
if let paymentTransaction : SKPaymentTransaction = transaction as? SKPaymentTransaction {
switch paymentTransaction.transactionState {
case .Purchasing :
print("Purchasing")
case .Purchased :
self.deliverProduct(paymentTransaction.payment.productIdentifier)
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
break
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
break
case .Restored:
print("Restored")
self.restoreTransaction(paymentTransaction)
break
default:
print("DEFAULT")
// PRESENT A USER FOR UI about not being able to make payments.
break
}
}
}
}
//MARK: Deliver Product
func deliverProduct(product : String)
{
self.validateReceipt { status in
if status
{
self.delegate.transactionCompletedForRequest(product)
}
else
{
print("Something bad happened")
}
}
}
//MARK: Receipt Validation
func validateReceipt(completion : (status : Bool) -> ()) {
let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL
let receipt: NSData = NSData(contentsOfURL: receiptUrl!)!
let receiptdata: NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let dict = ["receipt-data" : receiptdata]
let jsonData = try! NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions(rawValue: 0))
let request = NSMutableURLRequest(URL: NSURL(string: ReceiptURL.sandbox.rawValue)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.HTTPBody = jsonData
let task = session.dataTaskWithRequest(request, completionHandler: { data, response, error in
if let dataR = data
{
self.handleData(dataR, completion: { status in
completion(status: status)
})
}
})
task.resume()
}
func handleData(responseDatas : NSData, completion : (status : Bool) -> ())
{
if let json = try! NSJSONSerialization.JSONObjectWithData(responseDatas, options: NSJSONReadingOptions.MutableLeaves) as? NSDictionary
{
if let value = json.valueForKeyPath("status") as? Int
{
if value == 0
{
completion(status: true)
}
else
{
completion(status: false)
}
}
else
{
completion(status: false)
}
}
}
}
@xkenpachi
Copy link

Hi,

Where do i need to call the function : validateReceipt ?
I mean in viewDidload?

thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment