react-native-in-app-utils: The purchase works but (sometimes) invalid/no response is returned?
We are using this library to handle in app purchases in a production app and approximately 1 every 10 users that try to purchase a subscription report that the payment fails. However, if they try to purchase it again, the AppStore responds that they’ve already purchased that product (which we’ve checked in the AppStore console that it’s true). So, apparently the purchaseProduct function always works, but it randomly doesn’t return or returns an invalid response/error. Is this happening to anybody? Any solution?
This is the code we are using:
if (Platform.OS === "ios") {
InAppUtils.purchaseProduct(
config.inAppPurchases.ios.productId,
(error, response) => {
if (response && response.productIdentifier) {
this.props.dispatch(
makeIosSubscription({
transactionId: response.transactionIdentifier,
transactionReceipt: response.transactionReceipt
})
);
}
}
);
}
Unfortunately I cannot confirm if in those cases the callback is never called, or is called with an error/invalid response (even though the purchase was successful). We’ll try to log that and I’ll update this issue with more info.
Thanks
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 7
- Comments: 27 (4 by maintainers)
This is not an issue with this lib.
When a users initiates a purchase 2 things can happen:
User is logged in with Apple ID and payment method has been added to iTunes and is not expired.
User is not logged in or has no/expired payment method on iTunes.
For 1, purchase will go through and a transaction with state
purchasedwill be added to the queue.For 2, Apple will see that user cannot complete the purchase. A transaction with state
failed(purchase cancelled with error codeESKERRORDOMAIN2) will be added to the queue and user gets directed to AppStore to login and/or set up their payment method. The user will then complete the purchase and be directed back to your app. A transaction with statepurchasedwill be added to the queue. There will be afailedandpurchasedtransaction in the queue. Not sure why Apple does this.You will be receiving both the
failedandpurchasedtransaction when the user gets directed back to your app. This lib will pick up the first one, which will be thefailedone and trigger a purchase failed error.You can see what the error codes mean here: https://github.com/chirag04/react-native-in-app-utils/issues/15#issuecomment-230844435
You need to catch
ESKERRORDOMAIN2errors and get the next transaction in the queue. This will be thepurchasedtransaction. This is the one you need. The current version of this lib does not have the ability to get the next transaction in the queue.Use can use my fork here. My fork adds optional promise support and helper methods.
To install:
npm i --save https://github.com/superandrew213/react-native-in-app-utils#listen-for-purchase-eventYou need to do something like this: (Don’t just copy and paste this code. I just quickly made it up. Make sure you understand what is happening. We can’t test it in dev mode, you will only know if it works once you have released it.)
We ended un implementing a workaround that worked: When the purchaseProduct method returns an error, immediately call the restorePurchase method and you’ll get the right receipt.
We are seeing the same issue.
We are seeing
ESKERRORDOMAIN0with message:Cannot connect to iTunes StoreI don’t have a link, unfortunately.
I’m getting this and it’s causing a lot of angry customers, especially in the restore purchase flow. I will likely switch to https://github.com/dooboolab/react-native-iap.
They describe redesigning the library to not use a promise or callback flow, and instead use an event pattern. I believe this is what is resulting in some of the issues we’re seeing here, not properly handing events in the transaction queue.
You don’t need to call
IAU.shouldFinishTransactions(updated my comment above). My purchase flow is a bit more complicated and I need to manage all transactions manually.You just need to call
InAppUtils.getPurchaseTransactions. It will get (and finish) the remaining purchase transactions in the queue.