appReceipt is empty string

I’m trying to convert an existing iOS game to be subscription-based, and so I need to check the original app version to see if the customer purchased the old version, as required by Apple’s developer terms. I’m using code based on the final example from this page of the Unity manual.

(I’ll note that none of the Unity classes used here are documented in the Unity scripting API–is there a difference place I should be looking for info?)

        ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
        IAppleConfiguration appleConfig = builder.Configure<IAppleConfiguration>();
        string receiptText = appleConfig.appReceipt;

At this point, when I test my app on test device #1 in TestFlight, receiptText is an empty string. (There’s more code after this point to validate the receipt and examine its contents, but obviously none of it works with an empty input.)

Restoring purchases does not change the result.

Test device #2 does NOT get an empty string, and on that second device the receipt validates and parses successfully. (Though I’m suspicious it’s a fake sandbox receipt rather than real one–still investigating.) So I’m reasonably sure the code is basically correct.

One possible reason for the difference is that device #1 bought the game, whereas I’m moderately sure device #2 did not. (That was the point–to test both behaviors. Currently, neither is working as expected.)

Why might I get an empty string here? What should I do about it?

You are mixing receipts. Do you want the app receipt where the user bought the app itself on the App Store, or the purchase receipt? I’ve never used IAP to obtain the app receipt. The link you referred to is using the product receipt, not the app receipt. They are separate. The product receipt is available when the user makes an IAP purchase within your game. The updated docs are here https://docs.unity3d.com/Packages/com.unity.purchasing@3.2/manual/UnityIAPGoogleConfiguration.html

JeffDUnity3D, before continuing this conversation, could you please review this old Unity forum thread , in which you say that you don’t support app receipts , and then subsequently agree with a user that you were mistaken and the app receipt can be obtained in exactly the way I’m trying to do it , and then a year later when another user necros the thread you go BACK to saying that there is no way to get the app receipt .

Next, note that Unity specifically refers to the thing I am obtaining here as an “appReceipt” (line 3 below), and that (after being validated) it has a field called “originalApplicationVersion” (line 6 below):

ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
IAppleConfiguration appleConfig = builder.Configure<IAppleConfiguration>();
string receiptText = appleConfig.appReceipt;
byte[] receiptData = System.Convert.FromBase64String(receiptText);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
Debug.Log("originalApplicationVersion = " + receipt.originalApplicationVersion);

(In the sandbox environment, the above code successfully retrieves the “1.0” placeholder value that Apple says it always gives in the sandbox.)

Then, please tell me if you are still certain that this is not the app receipt?

If you are certain, then what is the correct way to get the app receipt? Checking the original purchase version of the app is not just an obvious feature, it is specifically required by Apple when converting a paid app to subscriptions! I don’t understand why Unity doesn’t have a tutorial covering specifically exactly this usage case.

I did not say you can’t get the app receipt, I mentioned you appear to be mixing receipt types. The receipt validator was designed for the product receipt. But it’s not very smart and only does the equivalent of a CRC check. So if both receipts were both base64 encoded, it would probably validate the app receipt too. I haven’t tested.

Well, setting aside the question of what I’m doing with the receipt once I have it, which receipt am I obtaining with the code that I posted, and why is Unity giving me an empty string for that receipt?

Which receipt are you talking about. The app receipt? Did this user purchase this same app previously? And now it’s back in TestFlight? Sorry if I’m not quite following.

I have a game that is already published on the app store, and follows the traditional paid model where a customer pays a one-time fee for permanent access to the game. I want to change this game to use a subscription model, where the customer pays a (smaller) recurring fee to get access to the game for a limited time, using Apple’s auto-renewing subscriptions.

As required by both common sense and the explicit terms of Apple’s developer agreement, I want people who already bought the game under the old model to continue to be able to play it, without buying a subscription. This means I need to check whether a given user bought the previous version of the game. I am given to understand that the appropriate way to do this is to check the app receipt.

After a surprising amount of effort researching something that seems like it ought to be a completely standard and well-supported use case, I found this page of Unity documentation, which (at the bottom of the page) obtains a string that Unity’s API refers to as an “appReceipt” and processes it into an object of type AppleReceipt, using this sample code:

#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX

var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Get a reference to IAppleConfiguration during IAP initialization.
var appleConfig = builder.Configure<IAppleConfiguration>();
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);

#endif

This AppleReceipt object has a field called “originalApplicationVersion”, which appears to be what I want.

Your first reply in this thread implied that this is not what I want. You said the “app receipt” is different from the “product receipt” and that this documentation is about the product receipt.

I am now asking you to please be very careful and double-check whether the thing the Unity API calls an “appReceipt” and appears to contain the information on the original version of the app is, as you claim, different from the “app receipt” that you say contains information on the original version of the app.

In the process of researching this topic, I came across multiple old Unity forum threads in which a series of Unity customers appeared to be attempting the exact same thing that I am attempting, and in which you, JeffDUnity3D, appear to have repeatedly misunderstood them and given them conflicting information, and responded to each new customer as if you had no recollection of any of the previous conversations.

So I would like you to exercise great caution in how you answer here, in recognition of the fact that this exact topic has been a recurring stumbling block for you, specifically.

For clarity, the app receipt refers to the receipt when the user purchases the game itself. The product receipt is different and separate, and refers to the receipt when a user purchases an IAP product. I don’t see where the confusion lies. Your code and the links you shared are correct, upon review. The product receipt is indeed different, we both agree on that! You are claiming that you have an empty app receipt. I got that. Either this user has not physically purchased this app previously, or there is something else going on (I would not know at this time, could be a bug). Restoring products would have no impact on the app receipt, only product receipts. That is why I made the observation that you seem to be mixing receipt types. So in summary, can you confirm that the user seeing the empty app receipt did indeed previously purchase this app on the App Store?

Well, if I use the same device to search for this app in the app store, the app store offers me a “download” button instead of a “buy” button. So Apple appears to believe that I own it.

It’s possible that the app was obtained using a promo code rather than a conventional purchase.

Got it, and it’s of course the same bundleID, etc. But I would think there would still be a receipt even with a promo code? Can you test with a new user?

I can’t change the Apple account on this particular device because it’s someone’s personal phone.

I have a second device I’m testing on, where I don’t believe the device has ever owned the game, and that’s giving me a valid-looking certificate with an originalApplicationVersion of “1.0”. I’m about 97% sure this is fake data. There was a version of the app published with a version string of 1.0, but Apple’s documentation (and one Unity forum post that I found) seem to indicate the originalApplicationVersion should contain the bundle code, NOT the version string. No version of our app has ever had a bundle code of “1.0”. And, as previously stated, I don’t believe this device ever owned any previous version of the game. Additionally, “1.0” happens to be the value that Apple uses in the sandbox version of their receipts, so it’s extremely plausible as a fake value.

So I’m pretty sure both devices are failing catastrophically, just in different ways.

I’m attempting to get access to some other devices to test on for comparison.

If this is on Sandbox, it may indeed be fake data for the app receipt. We have no control over it. Regardless, Unity IAP is just a passthrough service for the Apple StoreKit API, we receive the receipt data from Apple.

This is on TestFlight. To the best of my knowledge, this is the realest you can get without actually publishing your game to the world.

I don’t have any idea why we would be getting a fake receipt. I’m just saying the receipt looks suspicious.

If you have any ideas about how to verify the realness-or-fakeness of the receipt, or ways to change our testing protocol to be absolutely sure we will definitely not get a fake receipt, I would be happy to read them. The testing advice from Apple that I was able to find is sparse, and describes a UI that does not match what I’m seeing on any of my test devices.

You are doing it correctly. Either test with another user, another phone, or (unfortunately) in Production. I doubt the Sandbox has actual app receipts.

I found a discussion on StackOverflow (non-Unity-specific) that talks about asking Apple to “refresh” the app receipt if it isn’t present.

Does Unity do this? / Is there a way to make Unity do this?

They gave this sample code (again, this is not from a Unity context):

func getAppReceipt() {
    guard let receiptURL = receiptURL else {  /* receiptURL is nil, it would be very weird to end up here */  return }
    do {
        let receipt = try Data(contentsOf: receiptURL)
        validateAppReceipt(receipt)
    } catch {
        // there is no app receipt, don't panic, ask apple to refresh it
        let appReceiptRefreshRequest = SKReceiptRefreshRequest(receiptProperties: nil)
        appReceiptRefreshRequest.delegate = self
        appReceiptRefreshRequest.start()
        // If all goes well control will land in the requestDidFinish() delegate method.
        // If something bad happens control will land in didFailWithError.
    }
}

func requestDidFinish(_ request: SKRequest) {
   // a fresh receipt should now be present at the url
   do {
       let receipt = try Data(contentsOf: receiptURL!) //force unwrap is safe here, control can't land here if receiptURL is nil
       validateAppReceipt(receipt)
   } catch {
       // still no receipt, possible but unlikely to occur since this is the "success" delegate method
   }
}

func request(_ request: SKRequest, didFailWithError error: Error) {
   print("app receipt refresh request did fail with error: \(error)")
   // for some clues see here: https://samritchie.net/2015/01/29/the-operation-couldnt-be-completed-sserrordomain-error-100/
}

@Antistone Good catch! I will pass this along to the engineering team and get their feedback. I suspect we are not refreshing. Yes, it would be valuable to have a reliable app receipt for those users moving from your paid app to subscription based. We are focusing on moving to StoreKit2 so it may take some time to be included as a possible feature request. How about this? Unity - Manual: Store Extensions

Hello,

Was this “empty string” situation ever solved? I am having the same issue when trying to test a transition from premium to freemium. Are there any experiences as to the whether the proposed code example is working in production? Can it be tested somehow?

I am equally surprised as @Antistone that the move from premium to freemium is not something that is a standard case - whether on unity or on apple side. It feels very much like taking a step into the dark…

We eventually canceled our attempt at this. I don’t recall all the details of what we went through before it was canceled, but my general recollection is that we reached a point where we were pretty sure that there was literally no way to test with real, non-placeholder receipt data without actually publishing the app in the app store and releasing it to the general public. (It might have been that we got a receipt for the app itself but not for the subscription add-on? I don’t recall exactly.)

Apple provided some sort of fake receipt when running in test mode, but we couldn’t figure out any way to see a real receipt for our actual app, and therefore couldn’t confirm that they had the values or formats that we were expecting. For example, I seem to recall we had a discussion over whether the version was going to be represented by a user-facing version string like “1.3” or an internal integer build number like “432”, and the documentation seemed to say build number but the fake example certificate had a string with a decimal in it (or something like that), and we had no way to get real data to compare against.

We had some discussions about what sort of defensive code we could write to do an in-production test as safely as possible, but didn’t actually go through with it.

Overall this situation seems insane. Either we somehow missed a critical test path that we couldn’t find in Apple’s docs, Unity’s docs, or any of several blog posts we looked at, or else Apple has no serious support for a feature that their terms literally require you to implement when switching from one-time purchase to subscription.

Thanks for rapid response on this topic.
Rather depressing actually.
I have submitted a freemium version of the game but it got rejected on basis of “cluttering” the app store…
If i come up with something i will post it here…

the only option i can think of now is to release a new version featuring a (hard to find and not very interesting to press) information-button which can display the receipt text, the receipt and its information (once verified that the receipt text actually contains valid data)