Decode Apple Receipt
Verify with the server-side click here
/**
* ***********************************************************************
* SMINRANA CONFIDENTIAL
* __________________
*
* Copyright 2020 SMINRANA
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of SMINRANA and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to SMINRANA
* and its suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from SMINRANA.
* www.sminrana.com
*
*/
import SwiftUI
import StoreKit
import Combine
class AppStorageManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
@AppStorage("username") var username: String = ""
@AppStorage("password") var password: String = ""
override init() {
super.init()
SKPaymentQueue.default().add(self)
}
@Published var products = [SKProduct]()
func getProdcut(indetifiers: [String]) {
print("Start requesting products ...")
let request = SKProductsRequest(productIdentifiers: Set(indetifiers))
request.delegate = self
request.start()
}
// SKProductsRequestDelegate
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Did receive response \(response.products)")
if !response.products.isEmpty {
for fetchedProduct in response.products {
DispatchQueue.main.async {
self.products.append(fetchedProduct)
}
}
}
for invalidIdentifier in response.invalidProductIdentifiers {
print("Invalid identifiers found: \(invalidIdentifier)")
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Request did fail: \(error)")
}
// Transaction
@Published var transactionState: SKPaymentTransactionState?
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func restorePurchase() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
struct PaymentReceiptResponseModel: Codable {
var status: Int
var email: String?
var password: String?
var message: String?
}
// SKPaymentTransactionObserver
// This gets called when transaction purchased by user
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
self.transactionState = .purchasing
case .purchased:
print("===============Purchased================")
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
let receiptString = receiptData.base64EncodedString(options: [])
// Send receiptString to server for further verification
}
catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
case .restored:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
print("==================RESTORED State=============")
self.transactionState = .restored
case .failed, .deferred:
print("Payment Queue Error: \(String(describing: transaction.error))")
queue.finishTransaction(transaction)
self.transactionState = .failed
default:
print(">>>> something else")
queue.finishTransaction(transaction)
}
}
}
// This gets called when a transaction restored by user
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("===============Restored================")
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
let receiptString = receiptData.base64EncodedString(options: [])
// Send receiptString to server for further verification
}
catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
}
}