cordova-plugin-inapppurchase icon indicating copy to clipboard operation
cordova-plugin-inapppurchase copied to clipboard

transactionId inconsistency - Android

Open JohnScottMcNerney opened this issue 8 years ago • 8 comments

Android transactionId is different between "buy" and "restorePurchases" for a consumable product.

Details are shown below, but basically (1) "buy" : transactionId == receipt.purchaseToken (2) "restorePurchase" : transactionId == receipt.orderId.

The "purchase data" should be the same (or at least consistent), no matter the function that returned it....

Why is this an issue, you ask?

On my sever, I save every purchase for every user, so I can make sure each purchase is applied to the user that purchased it, and that every purchase is not re-processed (for a game, to make sure they only receive their purchased coins once).

I use the restorePurchases.transactionId as the unique purchase identifies in my database (ex: "GPA.1395-0061-3237-38356").

This is used because the voltrue2/in-app-purchase NODEJS module returns this same value ("GPA.1395-0061-3237-38356") as "orderId", making things consistent, so I can correlate the verification request to the verification response.

  • John

from inAppPurchase.buy

productId : "kf_coins_99" productType : "inapp" receipt : "{"orderId":"GPA.1395-0061-3237-38356","packageName":"com..app","productId":"kf_coins_99","purchaseTime":1484856489387,"purchaseState":0,"purchaseToken":"oknoanhaobleoniljhehhikb.AO-J1OzgFwHnaMcF6bB-iW6TQSLYRumjyCQVIYNCxzzb2L5Z6UUoLx_jCv9cEPjCgpnRGfr2Arf6Bq-8NQT3BoExmg0l29GWe75yma8hKeIANmObGNgh5k4uFOSszhO-s75Imzbe9Z63"}" signature : "" transactionId : "oknoanhaobleoniljhehhikb.AO-J1OzgFwHnaMcF6bB-iW6TQSLYRumjyCQVIYNCxzzb2L5Z6UUoLx_jCv9cEPjCgpnRGfr2Arf6Bq-8NQT3BoExmg0l29GWe75yma8hKeIANmObGNgh5k4uFOSszhO-s75Imzbe9Z63" type : "inapp"

from inAppPurchase.restorePurchases

date : undefined productId : "kf_coins_99" productType : "inapp" receipt : "{"orderId":"GPA.1395-0061-3237-38356","packageName":"com..app","productId":"kf_coins_99","purchaseTime":1484856489387,"purchaseState":0,"purchaseToken":"oknoanhaobleoniljhehhikb.AO-J1OzgFwHnaMcF6bB-iW6TQSLYRumjyCQVIYNCxzzb2L5Z6UUoLx_jCv9cEPjCgpnRGfr2Arf6Bq-8NQT3BoExmg0l29GWe75yma8hKeIANmObGNgh5k4uFOSszhO-s75Imzbe9Z63"}" signature : "" state : undefined transactionId : "GPA.1395-0061-3237-38356" type : "inapp"

Version of cordova

5.1.1

Version of iOS/Android

Android 6.0.1

JohnScottMcNerney avatar Jan 19 '17 21:01 JohnScottMcNerney

@JohnScottMcNerney did you find a solution to this?

I'm curious about restorePurchases -> state: undefined

I'm seeing this on my subscription statuses along with date: undefined, making it impossible for me to know if the user cancelled their subscription.

santekotturi avatar Feb 15 '17 06:02 santekotturi

@skotturi Sorry, but I am only doing CONSUMABLE purchases, not SUBSCRIPTIONs. As such, I don't really look at the "state" or "date". If you get "state: undefined" for a product correctly configured as a SUBSCRIPTION, you have an issue different than what I have.

JohnScottMcNerney avatar Feb 15 '17 13:02 JohnScottMcNerney

Guys if you can find any information about that, please write here. It can be helpful.

centrual avatar Mar 08 '17 20:03 centrual

@centrual I believe its impossible to check android subscriptions with the receipt on the client. You will need to use Google Play Store API: https://github.com/voltrue2/in-app-purchase#google-play-store-api

I've setup most of it but haven't got it fully working yet.

santekotturi avatar Mar 08 '17 22:03 santekotturi

@JohnScottMcNerney -- I know this is an old ticket, but did you ever solve this? I'm seeing the same thing, where the transactionId == purchaseToken after a call to buy(), but transactionId == orderId after a call to restorePurchases.

phiferd avatar Mar 22 '19 08:03 phiferd

This still seems like a bug (maybe in the Android API), but I solved this by using the transactionId from the purchaseData. So,

const validatedData = await iap.validate(receipt);
const purchaseData = await iap.getPurchaseData(validatedData);
const transactionId = purchaseData.transactionId;

In this case, the transactionId is the same in both the buy and restorePurchases scenarios.

Note that validatedData also have the purchaseToken, but I don't know if that will always be the same as the transactionId, so I decided not to use it.

phiferd avatar Mar 22 '19 08:03 phiferd

Actually, upon closer inspection, the issue is here:

https://github.com/AlexDisler/cordova-plugin-inapppurchase/blob/master/src/js/index-android.js#L70

and here:

https://github.com/AlexDisler/cordova-plugin-inapppurchase/blob/master/src/js/index-android.js#L114

Maybe this is just a workaround of some sort?

phiferd avatar Mar 22 '19 09:03 phiferd

Sorry, one more thing I noticed. The purchaseToken is available from the native restorePurchases call on android:

https://github.com/AlexDisler/cordova-plugin-inapppurchase/blob/master/src/android/InAppBillingV3.java#L375

So it seems like the line transactionId: val.orderId, in index-android.js is just a bug.

phiferd avatar Mar 22 '19 09:03 phiferd