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) }
        }
    }
    
  
}
Spread the love

Leave a comment