Our app is developed in Unity and built to iOS and Android. For iOS in-app purchases, we are using the Prime31 StoreKit plugin. We now use the 5/24/14 version of the plugin, but the issue was first noticed when we upgraded to the 3/14/14 version.

The behavior occurs when performing certain actions such as restoreCompletedTransactions(). It will first say "paymentQueueRestoreCompletedTransactionsFinished" and display information about the purchase including its transactionState.

paymentQueueRestoreCompletedTransactionsFinished
transactionUpdatedEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored

productPurchaseAwaitingConfirmationEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored

Then it attempts to finish all pending transactions. If there are any stuck transactions (Transaction comes back after finishTransaction: has been called on it), the console will report that it is telling the transactions to finalize, but will say that 0 have updated, except the first time, which will say all of them have updated:

transactions that have been updated by the payment queue: 0
transactions that are currently in the payment queue (and possibly stuck there): 59
finishing transaction: 1000000113168314 : test_monthly
StoreKit: transaction completed: <SKPaymentTransaction: 0x190d49f0>
finalizing and asking the payment queue to finish transaction: <SKPaymentTransaction: 0x190d49f0>
finishing transaction: 1000000113168318 : test_monthly
....

For each of the 59 transactions, it will display those three lines ("finishing transaction", "transaction completed", "finalizing..."), and once it has gone through all 59 of them, it will repeat the entire block, from "productPurchaseAwaitingConfirmationEvent" (with a different transaction id) down to the last "finalizing" of the 59th transaction, for 59 times total. As a result, if there are n transactions, it will create n^2 log messages. When I pressed other buttons in that scene, such as "Get Saved Transactions" and "Finish All Pending Transactions", it told me that there are 0 transactions to be saved or finished.

Afterwards, if it loops over all of the transactions enough times, it updates all of the transactions as restored, printing these lines out n^2 times:

purchaseSuccessfulEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168959, transactionState: Restored
....

Finally, it will remove each transaction from the paymentQueue, printing these lines only n times (but will re-add them the next time you restore):

paymentQueue:removedTransaction: <SKPaymentTransaction: 0x1961d070>
...

Here are the problems with this behavior:

  1. It takes a long time to cycle through these transactions, and the app is hung while this is happening.
  2. If n is sufficiently large (roughly more than 25 transactions), the app runs out of memory and crashes once it loops through enough times. It crashes during the section when it is looping over the transactions stuck in the payment queue.
  3. Each test account has a finite lifespan now. Numerous transactions may get stuck each time the account is used, and eventually the account may become unusable because store actions that loop through the stuck transactions will always crash if n is sufficiently large.

The behavior happens within the Prime31 plugin code, and is reproducible in the demo scene provided with the plugin.

  1. Create a new project and import the Prime31 StoreKit plugin package.
  2. Put the names of your products under the "Request Product Data" button section in StoreKitGUIManager.cs.
  3. Create a sandbox store and fill it with products (we have a non-consumable and a monthly subscription with a one-week free trial).
  4. Set the bundle id of the project to match the bundle id for your sandbox.
  5. Set the version number of the project to a high number (In our case, it's about 1200 or higher. I am not sure why, but I noticed that it loops over many more transactions if the version number is set at 1200 or above (dangerous, may crash) and loops for a much smaller number for versions below 1200 (safer). I think it coincides with the version in which we started to use free trials.)
  6. Build to iOS.
  7. Create a test user and have it perform many transactions with your store, which should accumulate some stuck transactions in the payment queue.
  8. Click on the restore button and enter the login and password of that test account and watch the console.

Here are my questions:

  1. Does this behavior only occur in sandbox, or can it occur in live production as well? Either way, how can we verify that it won't happen in live production or that any fix we may do will not break live production?
  2. How can we fix this problem or create a workaround that will allow us to restore transactions or other functions properly without experiencing the issue?
  3. If we can do (2), can we use the app and restore functionality with old accounts, or would we no longer be able to use them and must create new accounts that have not had any transactions before?
0

There are 0 best solutions below