How to clear appStoreReceiptURL in-app array

After a lot of testing I end up with a broken appStoreReceiptUR file.


On the appdelegate I read the appStoreReceiptURL and then I validate the receipt as explained here https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/ValidateAppStoreReceipt.pdf


and I get a lot of pending in_app transactions to finish (just showing two below)

{

environment = Sandbox;

receipt = {

"in_app" = (

{

"is_trial_period" = false;

"original_purchase_date" = "2015-06-28 18:07:10 Etc/GMT";

"original_purchase_date_ms" = 1435514830000;

"original_purchase_date_pst" = "2015-06-28 11:07:10 America/Los_Angeles";

"original_transaction_id" = 1000000161134923;

"purchase_date" = "2015-06-28 18:07:10 Etc/GMT";

"purchase_date_ms" = 1435514830000;

"purchase_date_pst" = "2015-06-28 11:07:10 America/Los_Angeles";

quantity = 1;

"transaction_id" = 1000000161134923;

},

{

"is_trial_period" = false;

"original_purchase_date" = "2015-06-29 17:16:29 Etc/GMT";

"original_purchase_date_ms" = 1435598189000;

"original_purchase_date_pst" = "2015-06-29 10:16:29 America/Los_Angeles";

"original_transaction_id" = 1000000161282043;

"purchase_date" = "2015-06-29 17:16:29 Etc/GMT";

"purchase_date_ms" = 1435598189000;

"purchase_date_pst" = "2015-06-29 10:16:29 America/Los_Angeles";

quantity = 1;

"transaction_id" = 1000000161282043;

}


);

};

status = 0;

}

How can I retrieve those SKPaymentTransaction objects to then call.

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

Accepted Reply

This is very strange - Is this issue happening in the sandbox or production environments. In either case, this is an iTunesConnect issue to be investigated. If you do report this to iTC, they are likely to point you to DTS. On my part, I can only help you collect additional information which I can then present to iTC for them to investigate. Looking at this differently - is this in the sandbox. If so, try creating a new testuser and see if the problem persists with the new test user. I'm going to assume that it doesn't. However, if this issue is with the production environment, this would best be handled as a DTS incident.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Replies

The in app purchases which appear in the app receipt include both current and all previous in app purchases transacted by the user - with the exception of consumable purchase types which the app has called finishTransaction on. You asked how the application could acknowledge the transactions associated with the purchase of these items. The application receipt contains a history of prior purchases, but by itself cannot be used for completing transactions.


The acknowledgement process is handled through the updatedTransactions delegate method. When the delegate method is called, iterate through the transactions parameter to process each transaction (if there is more than one) Take a look at the SKPayment productIdentifier to know what was purchased and validate the receipt, if this is part of the process. The app then provides the associated content, then calls finishTransacton using the transaction parameter passed in the call. The app can only get the transaction identifier when the updatedTransactions delegate method is called.


If there is the case that a transaction is incomplete, StoreKit tracks this and watches for the app to ask for incompleteTransactions. This occurs whenever the addTransactionObserver call is made, or when the transactionObserver is active and the in app purchase app moves from the background to the foreground. When an incomplete transaction is detected, the StoreKit dialog may be presented to have the user authenticate themselves and the updatedTransactions delegate method is called, similar to when responding to a successful addPayment call. The app has another chance to process the transaction.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Now that I re-read the question, I see that there is the thought that the application receipt, in_app array is showing the incomplete transactions - this is not the case. As I mentioned in my previous response, the in_app array is a "living" history of purchases made by the user with the app. In a different forum posting, the question was asked - how big can the application receipt grow to. I checked with StoreKit engineering and there is no limit.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

yes Rich, that's what I understand from the documentation. "with the exception of consumable purchase types which the app has called finishTransaction on."


I have a lot of consumable purchases in the in-app array result of a bad implementation of the InAppPurchase flow I had.


I am calling the addTransactionObserver and doing additional purchases, and when updatedTransactions delegate is called it only includes the newest transaction and I finish the transaction. Everything works for new purchases, but those old consumable purchases are kept in the in-app array.


How can I force those "not finished" consumable purchases transactions to call the delegate so I can do finishTransaction?

This is very strange - Is this issue happening in the sandbox or production environments. In either case, this is an iTunesConnect issue to be investigated. If you do report this to iTC, they are likely to point you to DTS. On my part, I can only help you collect additional information which I can then present to iTC for them to investigate. Looking at this differently - is this in the sandbox. If so, try creating a new testuser and see if the problem persists with the new test user. I'm going to assume that it doesn't. However, if this issue is with the production environment, this would best be handled as a DTS incident.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

yes, the issue is in the sandbox. Just tried a new testuser and It's working flawless

When you execute addTransactionObserver (either becaiuse the user taps 'check for earlier purchases' or because the app does that whenever it launches) all unfinished transactions will result in a call to updatedTransactions (but see a point of confusion below). Once you finish all transactions that come into updatedTransactiuons you are done. If the receipt contains extra purchases that is irrelevant.


Here is a possible 'point of confusion' - what if a user logs into a different iTunes account and makes a purchase then logs out of the account before their transaction makes a call to updatedTransactions and before you finish their transaction? Will their purchase result in an entry in the receipt but a failure to send a call to updatedTransactions until you log into their account? Could that be the source of your mystery receipts? Just guessing here.

You raise an interesting point. However, let me just comment on the contents of the application receipt. The workings of the transactionObserver is something I will investigate later. For a production app, the application receipt will only contain purchases associated with the user account that installed the app. For example, even if the iTunes and App Store settings were cleared of an account, if the SKReceiptRefreshReq call is issued from a production app, the StoreKit dialog will use the user account that was used to install the app. Only the password field can be editted.


In the sandbox environment, if the app is installed by Xcode, there is no current user, so it might be that one account was used to make the consumable purchases that were incomplete, and a newer test user account was used to make purchases later on in the problem case above. This is solely a guess. Deleting the app and installing a newer version via Xcode should mean that there is no app receipt. There's more to learn about this case and when the consumable purchases appear in the receipt.


As to multiple users and the transactionObserver, there's more to investigate here....


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

You wrote: "For a production app, the application receipt will only contain purchases associated with the user account that installed the app."


In the production environment, can I log out of the App Store from one account, log into the App Store using a different account and then buy an IAP using that different account? If not, where in the process am I required to log into the account of the user who loaded the app onto the device (i.e. 'bought' the app). Does the same apply to the sandbox?

I need to clarify my response as my previous response is not totally correct. As you point out, the user can log out of the iTunes and App Store setting, and another user can launch the in app purchase app and make a purchase - what happens with the application receipt. In this case, the application receipt is updated to match that for this second user. The application receipt will no longer show purchases made by the original user who installed the app. At this point, iOS associates the app with the second user and has updated the application receipt to the second user. If the SKReceiptRefreshRequest is issued at this point, the second user's name will be present in the StoreKit alert and that users password is expected for the receipt to be refreshed.


If later on the restoreCompletedTransaction call is issued with the second user's setting still in the iTunes/App Store settings, then the restore process will restore purchases made by the second user. The first user can clear out the iTunes / App Store settings preference at this point, but if they trigger the SKReceiptRefreshReq, the second user will still be in the StoreKit password dialog. At this point, if the first user (device owner) enters the iTunes /App Store, clears the setting, and re-enters the app, if they either purchase an item or trigger a restoreCompletedTransaction, the StoreKit dialog will allow the user to enter both user name and password. Upon completion, the application receipt is updated to the owner account - all info about the previous second user is no longer in the application receipt.


The same applies in the sandbox

rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Two comments:


regarding restoreCompletedTransactions, I hope what you say is not true. Can I buy an IAP to anApp, tell all my friends to download the app and then go from device to device restoring my IAP on their devices? I think that restoreCompletedTransactions only works if the 'purchaser' of the app is also the 'purchaser' of the IAP.


regarding the OP issue - is it then possible that this phantom receipt indicates that there are transactions waiting to be downloaded as soon as the device logs into the correct test users account - the one who 'purchased' the app, not the one who thinks they completed all transactions.

I have same issue on consumable in app purchase items. I call finishTransaction method on every updateTransaction delegate, so there cannot be a 'living' purchase transaction on receipt. Is that right?


Below is a real receipts which have multiple in_app receipt of same user. (It happened productioin environment)


<23/June/2015>

in_app:[

{

quantity:3,

product_id:CPI010001,

transaction_id:30000097249602,

original_transaction_id:30000097249602,

purchase_date:2014-04-19 06:35:30 Etc/GMT,

purchase_date_ms:1397889330000,

purchase_date_pst:2014-04-18 23:35:30 America/Los_Angeles,

original_purchase_date:2014-04-19 06:35:30 Etc/GMT,

original_purchase_date_ms:1397889330000,

original_purchase_date_pst:2014-04-18 23:35:30 America/Los_Angeles,

is_trial_period:false

},

{

quantity:7,

product_id:CPI001000,

transaction_id:30000160744395,

original_transaction_id:30000160744395,

purchase_date:2015-06-23 08:00:24 Etc/GMT,

purchase_date_ms:1435046424000,

purchase_date_pst:2015-06-23 01:00:24 America/Los_Angeles,

original_purchase_date:2015-06-23 08:00:24 Etc/GMT,

original_purchase_date_ms:1435046424000,

original_purchase_date_pst:2015-06-23 01:00:24 America/Los_Angeles,

is_trial_period:false

}

]


<8/July/2015>

in_app:[

{

quantity:3,

product_id:CPI010001,

transaction_id:30000097249602,

original_transaction_id:30000097249602,

purchase_date:2014-04-19 06:35:30 Etc/GMT,

purchase_date_ms:1397889330000,

purchase_date_pst:2014-04-18 23:35:30 America/Los_Angeles,

original_purchase_date:2014-04-19 06:35:30 Etc/GMT,

original_purchase_date_ms:1397889330000,

original_purchase_date_pst:2014-04-18 23:35:30 America/Los_Angeles,

is_trial_period:false

},

{

quantity:3,

product_id:CPI010001,

transaction_id:30000163131706,

original_transaction_id:30000163131706,

purchase_date:2015-07-08 04:37:05 Etc/GMT,

purchase_date_ms:1436330225000,

purchase_date_pst:2015-07-07 21:37:05 America/Los_Angeles,

original_purchase_date:2015-07-08 04:37:05 Etc/GMT,

original_purchase_date_ms:1436330225000,

original_purchase_date_pst:2015-07-07 21:37:05 America/Los_Angeles,

is_trial_period:false

}

]


Can you check the reason of this issue?

And is there a method to flush past consumable in_app receipt data?

The question is what IAP purchases are retained in the receipt. The documents indicate that autorenewables, non-consumables and, most recently, non-renewing subscriptions are retained. The documents suggest that consumables are washed away after an update which occurs each time there is a new purchase. However, for weeks before non-renewing subscriptions were switched from 'washed away' to 'retained' they were sometimes retained and sometimes washed away. You are now reporting the same behavior for consumables. It has been seen before.


If you are using the receipt to credit an app with IAPs you must check the purchase date or the transaction id of each purchase and be sure it is appropriate to credit it at that time. That means, for example, when you get a call to updatedTransactions, if you send the receipt for verification you need to also send the transactionId of the particular purchase you are exploring.

As I understand, your description of the potential problem is correct. However, when the restore is implemented, this means that you would first have had to clear out the user name in the iTunes and App Store Settings, performed the restore, which would trigger your account to be entered as the iTunes and App Store account in your friends devices. In this way, the restore process thinks that your account is the purchaser of the iAP for that app. But this can lead to other issues for the user of the device.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

If your original post up there is correct, all I would need to do on my friends' (all 200 of them) iPhones is:


Settings/iTunes & App Store/Apple ID:/Sign Out/Apple ID: - enter my ID and password/Run the app/restoreCompletedTransactions/


For completeness I would then sign out of the App Store on their device.


I'm hoping this actually does not work because, I thought, the restoreCompletedTransaction must be done by the same person who purchased the app - but I could be wrong. If I am wrong this is a bit of a large hole isn't it?

As i can see you implemented apple guidelines to read appStoreReceiptURL, i am unable to load payload from receipt file and then parse receipt locally using asn1c: https://forums.developer.apple.com/message/29366#29366

can you please help me out here, how were able to load receipt file data into payload.