Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syncing a consumable in-app purchase with a server

I am trying to figure out the best way to ensure that a user will not lose their consumable in app purchase.

However, I am starting to feel like this StackOverflow user.

After a complete transaction I want to send to a server that the user bought a consumable in app. However, the connection might fail at that point (the server is down or the user loses connection).

I was considering in that scenario to send the receipt as soon as the connection can be made again. However, from what I have read the receipt contains all in app purchases and I can't send only the receipt for the last bought item.

How can I ensure that the purchase made by the user was synced with the server?

like image 659
Tiago Almeida Avatar asked Jul 21 '14 16:07

Tiago Almeida


People also ask

Do in-app purchases work on multiple devices?

You can install your paid apps on as many of your devices as you like, so long as they are connected to the Google account used to purchase the apps.

Do I need a server for in-app purchases?

It should be noted that server validation isn't mandatory — in-app purchases will still work without it. It grants some advantages, though: Advanced payment analytics, which is especially important for subscriptions since everything that happens after the activation isn't processed by the device.

What is a consumable In-app Purchase?

Consumables are one-shot items, such as ammo, or stickers.


1 Answers

The solution is to not call

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

on the consumable purchase until it has been synced with the server. This way, the transaction will be delivered again to your observer every time it is set to observe the payment queue. You will need manage app side whether it's a purchase that has been delivered but not synced, or a new purchase.

Once you have synced the transaction with the server. You can call -finishTransaction:. See the "Finishing The Transaction" in the docs here:

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/DeliverProduct.html#//apple_ref/doc/uid/TP40008267-CH5-SW3

EDIT

So the user is charged by Apple, and Apple send you a SKPaymentTransaction object that represents the transaction. If the transactionState property of that transaction is SKPaymentTransactionStatePurchased, then it means Apple has processed the payment and the user has been charged.

Once you have received this SKPaymentTransaction object from the paymentQueue, you deliver the content to the user, and sync the transaction with your server. Once both of those have been successfully completed, you call -finishTransaction. Calling -finishTransaction tells StoreKit that you have successfully completed everything you need to do. -finishTransaction is a synchronous call, you are handing responsibility back to StoreKit, and you don't need to concern yourself with how that is communicated back to iTunes/Apple, StoreKit handles it all for you.

You should not call -finishTransaction until you have done everything you need to do. If something goes wrong (device battery dies, loss of internet connection, app crash), you will be delivered the same SKPaymentTransaction from the payment queue next time your observer is registered with the queue, and can try to sync again with your server. This will keep happening until you call -finishTransaction.

There is a scenario where the user is never able to sync with your server, never connects to internet again etc. That is out of your control, and at that point it is the responsibility of Apple to decide whether they charge the user.

It's also worth noting that the user can contact Apple and request a refund if they wish to.

like image 134
Sam Clewlow Avatar answered Sep 28 '22 05:09

Sam Clewlow