Handling of failed deferred IAPs (SK Payment TransactionStateDeferred) and remote verification failures

Handling of failed deferred IAPs (SK Payment TransactionStateDeferred) and remote verification failures
0

#1

This question is two main parts,

1)How does SDKBOX propose the handling of SKPaymentTransactionStateDeferred?
In the case that a user attempts to make a purchase, but has to get permission via ‘Ask to Buy’ on iOS, the transaction will be incomplete and should be completed at a later time.

There seems to be no documentation on this, will this result in a call to onCanceled() ? onFailure()?
onFailure also only returns a msg string, no sensible error code, so how can the app know that there is a purchase waiting to be completed at a later date or even show a sensible error to the user to get purchase permission and return later?
In the case that a user performs the following flow:

  • make purchase in-app
  • receive StateDeferred
  • close app
  • purchase is completed by parent
  • open app
    ^ At this point how the app to know that there is a pending purchase to be completed? What should be called at this point to complete the deferred purchase? finishTransaction() does not seem appropriate as the app does not know the SKU of the purchase that was deferred before it was closed

2)My second question is what is the correct flow for handling situations where a purchase was successful, but notifying a (self managed) server about the purchase failed (verification failed) due to issues such as network connectivity.
Is there any way to retrieve past purchases to try again? (These are consumable purchases which do not seem to be returned via restore()

I have a feeling this is what ‘setAutoFinishTransaction’ is designed for there is absolutely no documentation regarding what this setter does
What does this setter do? What is the behavior? What is the expected outcome? How is it to be used? Is it iOS only? (Some threads seem to imply this was added to android too but the library header says otherwise)
In the case that this is not implemented on Android what are we supposed to do in the case of failing to remote-verify a purchase and needing to try again at a later time.

Can we get some real documentation on this other than set auto invoke finishTransaction flag

Overall I feel extremely frustrated right now with the lack of any real documentation of a very critical SDK component and am on the verge of tearing it out and spending 1-2 days making platform-specific implementations for iOS and Android just to even understand what will happen in these edge cases.
I think if a library wants to ‘hide the details and make things easy’ for a developer, it needs to have very strong documentation to at least tell us that these cases are handled (the two cases above seem to not even be handled however)


#2

iOS has the concept of a transaction, need call finishTransaction after the purchase is complete, to end a purchase. setAutoFinishTransaction let developers can control the purchase flow. For example, developers can distribute the corresponding goods in the onSuccess event, and then invoke finishTransaction to finish the purchase flow.

finishTransaction is used to consume goods on Android platfrom.

for now, didn’t process SKPaymentTransactionStateDeferred event, not send corresponding event.
In my impression, iOS will proactively remind users that there is a purchase in progressing and guide the user to do the corresponding processing.

and we will update api description in PluginIAP.h


#3

Okay, what is the default SDKBOX behaviour though, transactions are automatically finished in onSuccess()?

Additionally, how do we know what sku to call finishTransaction() for if the app has been restarted? (Say a crash occurs on processing an IAP response, or persistent network error). I believe in StoreKit this is done via access to the SKPayments queue, but due to sdkbox abstracting this away, we no longer have access to this.
I feel that finishTransaction() shouldn’t require an sku and should finish any non-finished transactions that remain in the queue.

Sorry but what does this mean? Is it the same behavior as above? Does setAutoFinishTransaction() need to be set to true? What happens to transactions that this isn’t called for.

This is true, however how do we know when this is finished from the user side and when to do server verification of the purchase and how do we finishTransaction() for this.

Overall in my impression it feels like the answer to most of these questions is for finishTransaction() to be replaced or phased out with a replacement of finishAllTransactions(), together with some way to access the products, receipts, cipheredPayloads etc of transactions that are not yet finished().
With the current usage there is no clear way to finish more than one transaction of the same SKU even (say a user makes two purchases that both result in SKPaymentTransactionStateDeferred, how do we finishTransaction() on two of them and how do we know their sku after an app restart)


#4

Additionally, even with the current implementation, what is the behavior of finishTransaction()?
Does calling finishTransaction() on an sku with an incomplete transaction pending result in a call to onSuccess()?
Does this change any form of internal state? What do we send to be verified after calling this method in the case it is called outside of a successful transaction

All of these questions are referring to consumable purchases, as a note.


#5

@htlxyz
I have a similar problem.
Returns onFailure event and product when repurchasing for unused consumables.
However, the data to validate the receipt for product is null. Receipt data is required to validate the receipt and process the finishTransaction.


#6

default is true, so will finishTransaction automatically

save sku before purchase, and finishTransaction when you finish processing(e.g. verify receipt success or other thing)

so you can use the default value, let sdkbox finish transaction automatically.

on Android platform, the transaction is not same with ios. when you finishTransaction is meaning to consume a product. on Android platform, sdkbox will auto consume product by default. setAutoFinishTransaction can change this.

you can finishTransaction after you verify product in your server.

find SKPaymentTransaction from transaction queue, and then finishTransaction,(not find, just return) willn’t trigger onSuccess


#7

save receipt when get onSuccess.


#8

What is automatically? This is not quite good enough as a description when the purchase flow is critically important. Is this whenever onSuccess is received? Will SKPaymentTransactionStateDeferred ever be ‘automatically’ finished?

Why are we forced to save skus when SKPaymentQueue already implements this functionality? This sounds like a deficit of SDKBox.

also, if finishTransaction() is called after an app restart, and onSuccess() isn’t then called, how can we ever get the receipt to verify with our own server? It sounds like any transactions that finishTransaction() is called on that were deferred are just lost. How can we get receipts to validate/ apply these to the user?


In summary, I see three large problems in the sdk, two of which requires a fair amount of app-side functionality to combat (effectively making the whole finishTransaction() system redundant) and one a critical oversight with no solution

  1. There is no way to know what SKUs to call finishTransaction() on in the case server-side verification failed. Yes, it is possible to save the last sku that was used, but what if a user makes multiple failed purchases (this happens in production apps at scale), we have to build a system of tracking skus vs purchase states and try and keep them in sync across the two platforms’ finished/consumable flows? This defeats the whole point of the SDK

  2. There is no way to retrieve receipts for completed transactions that failed server verification due to unforseen issues. This requires building of app-side functionality to track all successful receipts, and adding of a second button to ‘complete purchases’ in the UI to allow re-checking of these purchases at a later time (or after a restart). This is also an undocumented requirement of the SDK, further eroding it’s usefulness.

  3. There is no way to receive the receipt for a deferred iOS transaction These transactions are utterly lost to SDKBOX, and there is seemingly no way to server-verify a transaction which has been put into SKPaymentTransactionStateDeferred
    This is a critical oversight


#9

will invoke finishTransaction Internal, before send onSuccess, onFailed, onCancel or onRestore.

when app launch, will send all transaction notified by updatedTransactions to developer. so developer will get onSuccess, onCancel event. and can do their process again.

but you can save sku by youself and use those two method, is better.

onSuccess will return receipt, and sdkbox will’t store receipt.

yes, we will support this ASAP


#10

Can we get a way to manually tell SDKBOX to perform this check for updated transactions? This would be more helpful to invoke manually than to rely on an app re-start.
I believe such a call would also be useful for processing pending transactions (as per the flow that needs to be supported) and receiving onSuccess() / onCancel() for all non-finished transactions that are successful.

I believe such a function would fix most remaining issues.
The specific function would be:
Updates status of all transactions for which finishTransaction() has not yet been called and calls onSuccess, onFailed, onCancel or onRestore appropriately.

Thanks, please let us know in this thread when this is done so that we can update asap.