Recovered and Unfinished Purchases
Not every paid purchase comes back through the Purchase() call that started it. The app can be closed between the payment and the delivery, or the store can confirm a payment after the purchase call has already answered. The SDK keeps every one of these purchases until your game finishes it, so the player always receives what they paid for.
There are two ways to receive them:
PurchaseRecoveredis raised when the store confirms a purchase that no purchase call is waiting for.GetUnfinishedTransactions()returns every purchase that is paid for and not finished yet, including the ones from earlier runs of the app.
Handle both. Each one hands you a Transaction you can deliver and finish.
Subscribe before configurations are initialized
Initializing configurations is what starts the store. While the store starts, it can confirm a purchase the player paid for in an earlier run, and PurchaseRecovered announces that purchase only once. Subscribe first, then initialize configurations:
playOpsSDK.Initialize();
// Before configurations are initialized: loading them is what starts the store,// and a purchase recovered at that moment is announced only once.var inAppPurchases = playOpsSDK.InAppPurchases();inAppPurchases.PurchaseRecovered += transaction => DeliverPurchase(inAppPurchases, transaction);
// Purchases owed from an earlier run are kept on disk, so they can be settled now,// before the store is up.foreach (var transaction in inAppPurchases.GetUnfinishedTransactions()){ DeliverPurchase(inAppPurchases, transaction);}
playOpsSDK.Configurations().Initialize();Grant before you finish
FinishTransaction() tells the SDK the player has received the product. Grant first, then finish:
private void DeliverPurchase(PlayOpsInAppPurchases inAppPurchases, Transaction transaction){ GrantProduct(transaction.ProductId); inAppPurchases.FinishTransaction(transaction);}If the app is closed after the grant and before the finish, the purchase is handed to you again on the next launch. If you finished first and the app closed before the grant, the player would have paid for nothing.
Finishing the same transaction twice does nothing. Once a purchase is finished, it is no longer returned by GetUnfinishedTransactions() or announced by PurchaseRecovered, so a purchase that reaches you both ways is delivered once as long as you finish it when you deliver it.
An unfinished purchase stays owed
A purchase that is paid for and not finished survives app restarts. It stays in GetUnfinishedTransactions() until your game calls FinishTransaction() for it. Read the list at every startup, so a purchase the player paid for in an earlier run is delivered on the next one.
Linking a recovered purchase to your own data
A Transaction carries the ids of the purchase it belongs to:
| Property | Description |
|---|---|
ProductId | The full store identifier of the product. |
TransactionId | The store’s id for this payment. |
OrderId | The store’s order id, when the store provides one. |
PurchaseSessionId | The SessionId of the purchase call that started it. |
EconomyChangeId | The economyChangeId you passed to Purchase(). |
PurchaseSessionId and EconomyChangeId are empty when the SDK could not identify the purchase call that started the purchase. Empty means unknown, not that no id was passed.