Hi,
I am working on In-App Purchase using StoreKit 2 and getting an error The file sandboxReceipt couldn't be opened because there is no such file when user does a first time purchase auto-renewal subscription. The second purchase, (using a different product ID for a 2nd time auto renew subscription)) does not return an error and correctly returns the second purchase receipt. Here are the sample codes and following example from https://developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api :
func purchasing(_ product: Product) async {
do {
if try await purchase(product) != nil {
if try await getReceipt() {
print("purchase successful")
} else {
print("purchase failed")
}
} else {
print("purchase failed")
}
} catch {
print("error", error.localizedDescription)
}
}
func purchase(_ product: Product) async throws -> Transaction? {
do {
// Begin a purchase
let result = try await product.purchase()
switch result {
case let .success(verification):
let transaction = try checkVerified(verification)
// Deliver content to the user.
await updatePurchasedIdentifiers(transaction)
// Always finish a transaction.
await transaction.finish()
return transaction
case .userCancelled, .pending:
return nil
default:
return nil
}
} catch {
return nil
}
}
func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
// Check if the transaction passes StoreKit verification.
switch result {
case .unverified:
// StoreKit has parsed the JWS but failed verification. Don't deliver content to the user.
throw StoreError.failedVerification
case let .verified(safe):
// If the transaction is verified, unwrap and return it.
return safe
}
}
@MainActor
func updatePurchasedIdentifiers(_ transaction: Transaction) async {
if transaction.revocationDate == nil {
// If the App Store has not revoked the transaction, add it to the list of `purchasedIdentifiers`.
purchasedIdentifiers.insert(transaction.productID)
} else {
// If the App Store has revoked this transaction, remove it from the list of `purchasedIdentifiers`.
purchasedIdentifiers.remove(transaction.productID)
}
}
// Send to third party payment provider
func getReceipt() async throws -> Bool {
// Get the receipt if it's available
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
print(receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
print("receiptString:", receiptString)
return true
}
catch {
/// The file `sandboxReceipt` couldn't be opened because there is no such file
print("Couldn't read receipt data with error: " + error.localizedDescription)
return false
}
} else {
return false
}
}