j3k0 / cordova-plugin-purchase

In-App Purchase for Cordova on iOS, Android and Windows
https://purchase.cordova.fovea.cc
1.3k stars 537 forks source link

iOS: Handling empty in_app array returned from receipt validation #301

Closed sfeast closed 8 years ago

sfeast commented 9 years ago

@j3k0 I think this is probably an easy one for you to answer.

I have an app with iOS auto-renewing subscriptions in production that is occasionally getting an empty in_app array returned from the receipt validation server. I've been told that this is either coming from someone trying to make the purchase on a jail broken device OR it's possible that the successful transaction notice was received before the app receipt was updated. In the latter case we should alert the user that there is a problem with the receipt and ask whether the user wants to refresh the receipt, see https://developer.apple.com/library/ios/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPT-MY_APP_VALIDATES_ITS_RECEIPT_WITH_THE_APP_STORE_VIA_PAYMENTQUEUE_UPDATEDTRANSACTIONS__AFTER_A_SUCCESSFUL_PURCHASE__HOWEVER__THE_RETURNED_RECEIPT_CONTAINS_AN_EMPTY_IN_APP_ARRAY_RATHER_THAN_THE_EXPECTED_PRODUCTS_

So basically I just want to verify that when we receive an empty in_app array after validating, we just need to call store.refresh() to perform the recommend receipt refresh - does this sound correct?

j3k0 commented 9 years ago

Well, if I'm not mistaken the plugin will retry validation 5 times if it fails (with an increasing delay, refreshing the receipt on each attempt). That should be enough "hide" the problem for non jail-broken devices.

sfeast commented 9 years ago

@j3k0 Ok nice. I think I'm seeing approximately what you're saying here https://github.com/j3k0/cordova-plugin-purchase/blob/master/www/store-ios.js#L119.

So just to be extra sure - our validator service should return the expired code (6778003 - aka store.PURCHASE_EXPIRED) in the case of in_app being empty so that this logic runs. Sound right?

westoj commented 8 years ago

@sfeast I would really appreciate you letting me know what you return from your validator to get it to work in this way? Simply sending the string/integer error code? Or something in JSON?

Are you using this method:

store.validator = "http://api. yourapp.com/validaterecipt";

store.when("my stuff").approved(function(product) { product.verify(); });

store.when("my stuff").verified(function(product) { product.finish(); });

sfeast commented 8 years ago

@OJcode14

I would really appreciate you letting me know what you return from your validator to get it to work in this way? Simply sending the string/integer error code? Or something in JSON?

It's sending a JSON object. I believe the format is:

{
  ok: <purchase status boolean>,
  data: {expires_date: <purchase expire timestamp>}
}

Are you using this method:

yes.

This wasn't obvious, ideally the docs would reflect this info.

westoj commented 8 years ago

I appreciate you getting back to me on this. I have been having an exceptionally hard time getting the validation and auto subscriptions to work correctly, if you could share any client side code with regards to this I think myself and others using this plugin would be eternally grateful.

atake831 commented 7 years ago

We have same issue.

@j3k0

Well, if I'm not mistaken the plugin will retry validation 5 times if it fails (with an increasing delay, refreshing the receipt on each attempt). That should be enough "hide" the problem for non jail-broken devices.

If we receive an empty in_app array, its error code should be INVALID_PAYLOAD, but store._refreshForValidation is occurred only when error code is store.PURCHASE_EXPIRED. https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/api.md#validation-error-codes https://github.com/j3k0/cordova-plugin-purchase/blob/master/www/store-ios.js#L584

Is it right ?? Could this implementation really void this issue ??

Best regards.