Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistency between iOS and macOS in App Store Receipt Handling within extractTransactionIdFromInAppReceipt(inAppReceiptContent:) #33

Closed
ronaldmannak opened this issue Feb 15, 2024 · 12 comments

Comments

@ronaldmannak
Copy link

I'm experiencing an issue where the handling of App Store Receipts seems to differ between iOS and macOS. This could be due to an error in my implementation, or it might be a bug in the AppStore Server Library.

I have an application that runs on both iOS and macOS. In the sandbox TestFlight environment, I fetch the App Store receipt and pass it to the server in the following way:

if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
           FileManager.default.fileExists(atPath: appStoreReceiptURL.path),
           let receiptData = try? Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped) {
            body = receiptData.base64EncodedString(options: [])
...

On the server side, extractTransactionId(appReceipt:) is used to extract the transactionId:

guard let transactionId = ReceiptUtility.extractTransactionId(appReceipt: body) else { 
...
}
// When macOS app calls the server, transactionId is the correct transactionId
// When iOS app calls the server, transactionId is a single digit (e.g. 0)

When the macOS app communicates with the server, extractTransactionId successfully retrieves the transaction id.

However, when the iOS app communicates with the server, the receipt parsing does not function properly. More specifically, at line 75 of ReceiptUtility.swift (result = String(utf8String)), a single digit is set during each loop, and this digit can vary from loop to loop. In contrast, when the macOS app uses this method, result is set to the full tx id during each loop.

@alexanderjordanbaker
Copy link
Collaborator

Is the iOS receipt generated from XCode or from the Sandbox environment?

@ronaldmannak
Copy link
Author

@alexanderjordanbaker Sandbox. Note that I have a single codebase for iOS and macOS. Come to think of it, I did have an issue logging into the sandbox account last night on one device. Let me check if I'm logged in using the same account on both iOS and macOS.

@ronaldmannak
Copy link
Author

I made sure I was logged in the same account and can confirm the server is not able to extract the transaction id from the iOS receipt, while it is able to extract it from the MacOS receipt.

FWIW, the receipts on iOS and Mac aren't the same size, the receipt on Mac is 151,248 bytes, while the iOS receipt is only 3,592 bytes (I measured the size on both on client and server just to be sure).

@alexanderjordanbaker
Copy link
Collaborator

@ronaldmannak This sounds a lot like the transaction id being generated isn't a "real" transaction id, that comes from Apple servers, but generated via the process described in https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode/. One ad-hoc way to check, does the much shorter iOS receipt end with a lot of AAAAs in the Base64? That is a common feature of how Xcode generates its receipts

@ronaldmannak
Copy link
Author

ronaldmannak commented Feb 16, 2024

@alexanderjordanbaker thanks, but I don't think that's the issue.

  1. I haven't set up the StoreKit configuration in Xcode.
  2. The issue occurs on TestFlight builds which don't use the local StoreKit configuration. (Correct me if I'm wrong but debug builds don't have App Store receipt files and only debug builds --not TestFlight-- use the local StoreKit configuration)
  3. ReceiptUtility.extractTransactionId(appReceipt:) doesn't check if a transaction Id is valid, it just extracts the transaction Id from the receipt offline
  4. ReceiptUtility.extractTransactionId(appReceipt:) doesn't return nil, instead it returns an invalid one-digit transactionId which is probably also an invalid format for a local configuration.
  5. The Mac TestFlight version of the app works as expected. It's just the iOS TestFlight version that isn't working. Both the Mac and iOS version use the same code.

I experimented a bit more and found out that if the client app extracts the originalTransactionID and passes that to the server (instead of the App Store receipt), the App Store Server Library validates the transactions from both iOS and macOS correctly.

What remains is that the App Store Server Library doesn't parse the iOS receipt correctly. I'd be happy to email both receipt files if that helps.

@alexanderjordanbaker
Copy link
Collaborator

Could you please file a ticket in Feedback Assistant (feedbackassistant.apple.com) with the receipts and post the FB number here please

@ronaldmannak
Copy link
Author

Will do!

@ronaldmannak
Copy link
Author

@alexanderjordanbaker submitted as FB13626068. Thanks in advance!

@alexanderjordanbaker
Copy link
Collaborator

@ronaldmannak Could you please include the receipts in the ticket?

@ronaldmannak
Copy link
Author

@alexanderjordanbaker sorry for the delay. I just added the receipt to the ticket.

@alexanderjordanbaker
Copy link
Collaborator

@ronaldmannak I've looked at the receipt and confirmed the shared receipt is an Xcode generated receipt signed by a local StoreKit CA that isn't using the Sandbox environment, but has environment Xcode

@ronaldmannak
Copy link
Author

Thanks for confirming, I appreciate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants