IdeasOnCanvas / AppReceiptValidator

Parse and validate App Store receipt files
https://mindnode.com/opensource
Apache License 2.0
353 stars 41 forks source link

Does anyone have a volume purchase app receipt file for testing VPP receipt support? #96

Open blach opened 1 year ago

blach commented 1 year ago

Hello,

I'm considering to change the business model of my app from paid up front to freemium. I was going to use AppTransaction in StoreKit 2 to check for the originalAppVersion. Unfortunately AppTransaction doesn't support the volume purchase program and triggers an Apple ID sign in when an app was purchased through the VPP.

I was looking at this library and it looks like it should be possible to check for UnofficialReceipt.provisioningType for ProvisioningType.ProductionVPP to check if the app was purchased through the volume purchase program.

  1. Does anyone have a sample VPP app receipt file so I could check a real-world example of how this would look like?
  2. Does a VPP app receipt file contain the originalAppVersion or is it nil?
  3. AppTransaction of StoreKit 2 has a field originalPurchaseDate that contains the original purchase date of the app itself while I cannot find this in the Receipt struct - only in InAppPurchaseReceipt. Is this not available outside of StoreKit 2, or is this field just not yet added to this library? I'm asking because if a VPP receipt did not contain the originalAppVersion, we could use the originalPurchaseDate of the app receipt instead.

Thanks for your help!

blach commented 1 year ago

Regarding the app's originalPurchaseDate: I have used the parseUnofficialReceipt method with a production receipt of my own macOS app and I can confirm that fieldType 18 (KnownUnofficialReceiptAttribute.date2) is the original purchase date.

For my MAS app, the field is logged as 18 = date2: 2013-03-22T20:53:21Z. The app was originally purchased on 2013-03-22 according to my App Store purchase history, so this matches.

blach commented 1 year ago

I have confirmed with two more iOS app receipts, that field 18 (date2) is indeed the originalPurchaseDate.

I would love to test this with a recent VPP app receipt, but I don't have access to one.

There is a screenshot of a VPP receipt at https://github.com/IdeasOnCanvas/AppReceiptValidator/pull/34

Unfortunately, both the "originalAppVersion" and the "date2" field are empty.

I don't know if this is only true for old receipts (that VPP receipt was created in 2017), or if this still holds true for VPP receipts in 2023.

So it would be great if anyone has access to a recent VPP receipt.

hannesoid commented 1 year ago

The tests currently only cover sandbox vs production unofficial domains but not vpp with examples, but I can confirm the results from the screenshot you linked are correct with old files (2017, 2018).

Unfortunately I also don't have access to recent VPP receipt files.

I could also and without any evidence imagine that Apple's receipt validation server API endpoint might offer info on this in one way or the other. In case this is something you are using too, it might be worth checking.

blach commented 1 year ago

Thanks for your reply! I don't currently use Apple's receipt validation service, so that's not an option to me.

In its lifetime, my app sold >3000 educational licenses using the VPP and I know that there are school courses that depend on it, so I think I won't be able to change the business model to free with in-app purchase because I cannot determine when or which version was bought through the VPP... 😔

The only option seems to be to release a new separate version of the app.

hannesoid commented 1 year ago

I see, yeah, if you don't want to depend on this undocumented receipt field, then that's probably the way to go.

lukaskubanek commented 1 year ago

@blach Neither I do have access to an actual VPP receipt, but I can confirm that the undocumented field for detecting a VPP purchase (or rather download) works reliably for the users of my app that transitioned from paid-upfront to a (custom) free trial with one-time purchase. However, to keep things simple, I don’t check when it was downloaded and hence whether it was paid for. All new VPP users get the app for free, as there is currently no way to sell in-app purchases (one-time or subscriptions) in this scenario, which is probably an even bigger limitation in your envisioned setup. You’d have to either offer a separate paid-upfront app or go with a custom implementation like e.g. Ulysses does.

blach commented 1 year ago

Thanks for sharing your experience! I've come to the same conclusion that I would not be able determine whether a VPP purchase was made for the original paid up-front version or for the new free+IAP version because there is no originalAppVersion or originalPurchaseDate in VPP receipts.

So I see several options:

  1. Change the business model of the existing app and just let new VPP users use the app for free (as you do).
  2. Publish a new free app with IAP and migrate all non-VPP users to this new app. This means you will lose all existing ratings and reviews. Also, it annoys the majority of users.
  3. Change the business model of the existing app to Free with IAP. Handle VPP users (see below).

For option 3 I have two solutions:

  1. Create a new paid up-front "volume license" version of the app as a new app record in App Store Connect. Request the app to be unlisted (see https://developer.apple.com/support/unlisted-app-distribution/). Detect VPP receipts in the existing app and direct users to the new volume license app. Maybe make the new "volume license" app free for a migration period of some months.
  2. Let support handle it: if schools contact support because the app doesn't work anymore, offer a refund. (I really don't like this option, I don't want to take away something they paid for)

I think option 3 with option 1 would be the best way to handle this. I just hope App review wouldn't object to having duplicate apps (with different business models) in the App Store. But I think if the second app is unlisted, it should be ok for them.

hannesoid commented 1 year ago

I think option 3 with option 1 would be the best way to handle this. I just hope App review wouldn't object to having duplicate apps (with different business models) in the App Store

As far as I remember, we didn't have issues with App review for this setup