Search code examples
iosapp-storepaymentstorekit

Attach additional data to consumable


I'm building an app that allows the purchase of digital items. Since we have many items available, we can't use non-consumables, so we are defining consumables for different price categories (2€ item, 3€ item, etc...).

When a user wants to buy a specific item, I get the consumable product for that specific price category, and start a purchase for that consumable. I then want to send the receipt to my server, validate it, and unlock the item in question.

Here's where I'm unsure on how to implement this. To get the receipt of a transaction, I need to listen to the PaymentQueue, so I get the receipt asynchronously and without context from the actual purchase.

How do I associate the receipt with the item the user purchased?

From what I know, there are two options:

  1. Attach data to my purchase, that I can read out of the receipt. Is that possible? That would be the ideal scenario.
  2. Store a list of item ids the user started buying, and when I get a receipt (or many receipts) from my queue, I simply look up the item ids, and send them along to my server. When the purchase is finished, I remove the item id from my list. Is this a viable solution? Can there be any problem with multiple devices, where a device gets a receipt although it didn't initiate the payment?

Solution

  • I was just going through the same problem in my app. Here's how I handled it:

    1. Attach data to my purchase, that I can read out of the receipt. Is that possible? That would be the ideal scenario.

    As you've probably found out, this is not possible.

    1. Store a list of item ids the user started buying, and when I get a receipt (or many receipts) from my queue, I simply look up the item ids, and send them along to my server. When the purchase is finished, I remove the item id from my list. Is this a viable solution? Can there be any problem with multiple devices, where a device gets a receipt although it didn't initiate the payment?

    This is pretty similar to what I did. Whenever a user makes a purchase, I create my own purchase object that gets added to an array in User Defaults. My payment object contains the App Store Connect product identifier as well as my app specific product info.

    When a receipt comes in on the PaymentQueue I do the following:

    1. Look for the first payment object in User Defaults that has a matching product_identifier.
    2. Remove the payment object(s) from the PaymentQueue. Note the PaymentQueue can receive an array of transactions.
    3. For each object/transaction pair, send to my server for validation and processing
    4. If all goes well, finish the transaction
    5. If something goes wrong on my end, I re-add the payment object to User Defaults and don't finish the transaction

    I did get some weird behavior when testing in Sandbox where I'd see old receipts appear on the PaymentQueue as well. In this case there isn't a matching object in User Defaults so I finish the transaction anyway.