'How to test receipt when Migrating iOS app from Paid to Freemium/Free in SwiftUI

I'm planning to update my app from a Paid app to a Free app with possible IAPs. I've come across the Receipt Validation, but I'm finding it very confusing. All I want to do is check the original_purchase_date of the Application, (NOT an IAP). All of those who purchased before the update, will have the original features unlocked automatically.

I've got this so far for loading the receipt:

#if DEBUG
   private let appStoreValidationURL = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")!
   #else
   private let appStoreValidationURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")!
   #endif

private func loadReceipt() {
    
    print("LOAD RECEIPT")
    // Get the receipt if it's available
    if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
        FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
        

        do {
            let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
            print(receiptData)
            
            // Handle the try. I skipped that to make easier to read
             let base64String = receiptData.base64EncodedString(options: [])

             // Encode data in JSON
             let content: [String : Any] = ["receipt-data" : base64String,
                                                   "password" : sharedSecret,
                                                   "exclude-old-transactions" : true]


                    let json = try! JSONSerialization.data(withJSONObject: content, options: [])

                    // build request
                    let storeURL = self.appStoreValidationURL

                    var request = URLRequest(url: storeURL)
                    request.httpMethod = "POST"
                    request.httpBody = json

                    // Make request to app store

                    URLSession.shared.dataTask(with: request) { (data, res, error) in
                        guard error == nil, let data = data else {
                       
                            return
                        }

                        do {
                            let decoder = JSONDecoder()
                            let response = try decoder.decode(ReceiptAppStoreResponse.self, from: data)
                        } catch {
                            // Handle error
                        }

                        }.resume()

            // Read receiptData
        }
        catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
    }
    }

The problem here is that it doesn't go past if let appStoreReceiptURL as there seems to be no receipt, even if I download the app from the app store and then build on top of it. Is there a way to test this? I need to see if the rest of the code is working to decode the receipt and get the original_purchase_date

Here is the rest:

private struct ReceiptAppStoreResponse: Decodable {

let status: Int?

let receipt: String?

let latestReceipt: String?

let latestReceiptInfo: [ReceiptInfo]?


enum CodingKeys: String, CodingKey {
    case status
    case receipt
    case latestReceipt = "latest_receipt"
    case latestReceiptInfo = "latest_receipt_info"
}

}

struct ReceiptInfo: Decodable {

let originalTransactionID: String?
let productID: String?

let expiresDateMS: String?

let originalPurchaseDateMS: String?

let isTrialPeriod: String?
let isInIntroOfferPeriod: String?

let purchaseDateMS: String?

enum CodingKeys: String, CodingKey {
    case originalTransactionID = "original_transaction_id"
    case productID = "product_id"

    case expiresDateMS = "expires_date_ms"

    case originalPurchaseDateMS = "original_purchase_date_ms"

    case isTrialPeriod = "is_trial_period"
    case isInIntroOfferPeriod = "is_in_intro_offer_period"

    case purchaseDateMS = "purchase_date_ms"
}

func getExpireDate() -> Date? {
    let nf = NumberFormatter()
    guard let expDateString = self.expiresDateMS, let expDateValue = nf.number(from: expDateString) else {
        return nil
    }

    /// It's expressed as milliseconds since 1970!!!
    let date = Date(timeIntervalSince1970: expDateValue.doubleValue / 1000)

    return date

}

}

How can I test this to make sure that I am able to get the date and that I can correctly set up the app depending on when they originally purchased it?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source