Non-renew subscription and receipt?

I am perplexed.


According to Apple's documenation here:


https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1


Receipts for in-app purchases of non-renewing subscriptions are retained in the receipt permanently. It says so in the above link as:


In-App Purchase Receipt

The receipt for an in-app purchase.

ASN.1 Field Type 17

ASN.1 Field Value SET of in-app purchase receipt attributes

JSON Field Name in_app

JSON Field Value array of in-app purchase receipts

In the JSON file, the value of this key is an array containing all in-app purchase receipts. In the ASN.1 file, there are multiple fields that all have type 17, each of which contains a single in-app purchase receipt.

The in-app purchase receipt for a consumable product is added to the receipt when the purchase is made. It is kept in the receipt until your app finishes that transaction. After that point, it is removed from the receipt the next time the receipt is updated—for example, when the user makes another purchase or if your app explicitly refreshes the receipt.

The in-app purchase receipt for a non-consumable product, auto-renewable subscription, non-renewing subscription, or free subscription remains in the receipt indefinitely.


Over the past few months of testing my app, this has indeed been the case. But now, the Sandbox environment is providing a the receipt only in the receipt resulting from the purchase transaction. Refreshing the app receipt no longer shows the in-app purchases.


What gives? Has there been a reversal of this policy or else what am I doing wrong?


The purchase process works fine; I finish the transaction and check the receipt. The recepit has the in-app purchase. However, if I issue a StoreKit request to refresh the receipt, the refreshed receipt doesn't show ANY of the non-renewable subscription purchases.


Any clues?

Thanks

Stu

Answered by K6TU in 74788022

I filed a Developer Tech Support request to request an explanation about which of the two referenced documents were correct and whether there had been a change of poilcy regarding which one was correct.


The initial response was that the first document was correct - non-renewing subscriptions were persisted in the app receipt. The person handling my reqest asked for some validation that dumped out all fields in the receipt which I provided. Again, showing that the purchases of non-renewing subsctiptions were not persisted in the receipt from the Sandbox.


First thing today I was asked to file a bug report as the developer handing my DTS confirmed what i was seeing.


Several hours later I got a follow up response that the change I was seeing was the result of a "bug fix" to the store logic and that now the SECOND document is considered the right answer. Developers are responsible for persisting non-renewing subscription status themselves and that the app receipt does not provide (as it did) a persisted record of the purchase of a non-renewing subscription.


The developer handling the case expressed surprise at this change but had confirmed the change with the AppStore development team.


So at least I now know what I have to do... although for the last three months of development after adding in-app purchases for this app using non-renewing subscriptions, the receipt information persisted all purchases.


No fuss, no muss and no annoucement of the change.


I am thankful that I learnt this BEFORE my app got approved for production and then had to deal with a bunch of unhappy customers.


Hopefully this thread saves others from the same headache.


Perhaps the App Store development team has a change of heart and reinstates this behavior but clearly there is still (without clarity across all doucment sources) a risk that the "bug" gets "fixed" again.


Stu

We are getting multiple reports that restoring non-renewing subscriptions now works again. It's unclear whether this is due to the iOS 9.1 update and/or something happening server side, but either way, it's good news!

By Jove Sir, you are correct!


I just tried a purchase of a non-renewing subscription via the Sandbox and all the prior purchases that had been made are now back in the receipt.


However, I have learnt my lesson regarding Apple and conflicting documents... When the docs conflict, go with the least attractive answer and make sure you can handle it.


The belt and suspenders solution here is to use BOTH the receipt and the iCloud key/value store. I don't want to have to explain to MY customers that Apple changed something and I can't make them whole.


Wow!


An official statement of what happened, why it happened and why the change has been reversed would be the class-act way to close this matter out - plus making the documentation consistent of course.


Stu

I've submitted rdar://23129725 to update the StoreKit guide to agree with the Receipt Validation PG on the handling of non-renewing subscriptions.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

So Rich, what do you think??? Can we rely on the receipt to give us a history of non-renewable subscriptions and therefore allow us to use it to copy a subscription to a new device or must we use the iCloud key-value file instead? And do you think either one is better or worse than the other? This question is for those of us who do not maintain a web server for this purpose.

I've queried the iTunes Production Support engineer who made the change - The "fix" to provide the history of non-renewing subscriptions in the application receipt is permanent. My interpretation is that permament means that if we make a change, we'll announce the change at a Developer Conference and announce the function to be deprecated for a period of time.


With regards to using iCloud as a means to restore non-renewing subscriptions, I've heard from my App Review contact - an application "can use iCloud to track the non-renewing subscriptions (NRS) but it can’t force the user to login prior to making the purchase. It has to be optional - that can can alert the user that iCloud is required to access the NRS content from their other iOS devices - and providing a way to register later, if users wish to have access to this content at a later time."


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Rich,


My understanding is an app using the iCloud Key/Value store can't tell whether the user is logged into iCloud or not. I checked with a test app that is provisioned for the key/value store and syncs correctly with other devices, but the [NSFileManager defaultManager].ubiquityIdentityToken value is nil. The app has Key-Value storage enabled as a capability but not iCloud Documents so I reason this is understandable.


So what is the recommended startegy for supporting Apple's requirement to make NRS available on all the users devices?


The only bullet proof strategy (beyond providing one's own server/backend to support persistence - adding the hassle of yet another account for the user) would seem to be to refresh the app-receipt and figure out the subscription status from the receipt.


Should an app using NRS provide a "restore purchases" button that utilizes the app store receipt and is this process then going to be accepted by the app review team?


Thanks

Stu

God bless you and all your colleagues. And from me - thanks!!!

If your issue regarding using the key-value file is: "The app has Key-Value storage enabled as a capability but not iCloud Documents so I reason this is understandable"

then enable the app (and your provisioning profile) for iCloud Documents.

I'm a StoreKit support specialist, but not so knowledgeable with iCloud. I'm checking with the DTS engineer who supports iCloud to see if there is a way to tell id the app has iCloud access. While there is an App Review requirement that an app provide a means for NRS to be restored, there is no recommedation as to how this shall be implemented.


As to basing the restore NRS function on the app using the Application receipt, this has been approved by App Review in the past - I can't speak officially for App Review so the final answer has to come from App Review.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

I implemented a "Restore Purchases" button to refresh the receipt and get the non-renewing subscription in-app purchases on other devices. It was rejected by the App Store and the explanation was that non-renewing subscription in-app purchases do not require a "Restore Purchases" button. This seems wrong. Anyhow, I titled the button something else and it was approved.

And I think you can also use:


if([[NSUbiquitousKeyValueStore defaultStore] synchronize]){

// get the expiration date

}else{

//alert - you need to log into iCloud to copy your subscription from one device to another

}

Thanks for the idea but alas it seems synchronize returns true if the sync from DISK works.


I tried this with the iPad in airplane mode and then also with the iPad logged out of iCloud - it always returns TRUE.


Oh well...

Appreciate the thought indeed.

Stu

Use the ubiquityIdentityToken by adding the iCloud documents capability.

I was debating doing that but it adds another layer of complexity support wise.


It's possible for the user (via the iCloud tab in Settings) to disable iCloud document storage on a per app basis. If they turn off access for my app, the appearance is the same as if they are not logged in - the ubiquityIdentityToken is then nil. I could provide an alert that says "You must be logged in to iCloud and have the app enabled in Settings etc" - I'll think about this approach.


In the meantime I'm going to handle this as follows:

  • Store the data I need in the iCloud key/value store (KVS) - if the user is logged into iCloud (and from polling my test users, it seems at this will be the typical case) then I'm done and data will automatically get propagated to the user's other devices the moment they run the app. No app receipt refresh etc required.
  • On the first purchase, remind the user that they must be logged into iCloud to access the subscription on their other device(s)
  • On my support web pages for the app, include an FAQ about accessing a current subscription on other devices


For the case where the user has purchased a subscription but on a device not logged into iCloud, once they login, then the data will be synced with the cloud version of the KVS.


I debated adding a receipt refresh if the app runs on a device AND the key for the required data is not present in the KVS. This would be in a situation where the user purchased a NRS on another device that is logged into iTunes (otherwise no purchase) but not into iCloud, then runs the app on a second device. Refreshing the receipt could result in an un-expected dialog for the user to login to iTunes. Something which in the past I suspect would have caused the app review team to reject the app.


Perhaps the best of both solutions (iCloud versus receipt persistence) would be for the big A to add a way of detecting that the KVS has been sync'ed with the cloud - and if not, then refresh the receipt with the persisted records of past NRS purchases?


It's a complex set of cases to handle given the conflicting requirements in the StoreKit documentation.


Hopefully the documentation will get updated, be consistent and then there is a single recipe to follow.

Stu

I actually think that the [[NSUbiquitousKeyValueStore defaultStore] synchronize] call returning YES is a bug and if that were fixed then you can simply detect that it returns NO and alert the user that to copy a subscription they need to log in to their iCloud Account for the app.


That said, there is a security issue you should consider. A user can 'share' their subscription with 100's of people if they create an iCloud Account that is a group iCloud Account - for example, one iCloud Account for all members of the XYZ Corporation. It is unclear to me whether this can actually be done but here's another feature that I do - in my key-value file I record a device identifier for each device that copies one of the subscriptions. For any subscription, when that number gets to 5 I tell the user to contact me to get additional subscriptions. This limit is not unreasonable because 1) over a one month period few people have more than 5 active iOS devices owned by them and 2) Apple limits the number of devices that can synch to iTunes to 5 and 3) I have a back door means of pushing any needed subscription to any person who contacts me. App Review has not objected to my limit of 5, although that doesn't mean they won't.

Non-renew subscription and receipt?
 
 
Q