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: ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored
productPurchaseAwaitingConfirmationEvent: ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored
Then it attempts to finish all pending transactions. If there are any stuck transactions (http://stackoverflow.com/questions/3139280/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:
finalizing and asking the payment queue to finish transaction:
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: 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:
...
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?
↧