Closed aesculus closed 1 year ago
Hi. Yes restorePurchases
is active. I just tested, works on my setup. This call is specific to iOS, it's what your app should do when the user hits the "Restore Purchases" button that Apple requires you to add to your app in certain circumstances: it'll basically replay all transactions so your app gets a chance to properly handle them if you need to store local data related to a user's purchase. Most generally this only applies to non-consumable, sometimes to subscriptions. It's a "heavy" call, it'll often request the user's AppStore credentials, and might take some time to process.
See the discussion section here for details: https://developer.apple.com/documentation/storekit/skpaymentqueue/1506123-restorecompletedtransactions
update()
on the other hand is a lightweight method that'll re-validate the application receipt (still on iOS), if you have a receipt validation service in place. It will refresh the user's purchases.
On Android, it'll fetch the list of purchases locally (as it's cached by the underlying SDK).
On all platforms, update() will also update the price of purchasable products. This is the method you might want to call if the user enters your Store screen a while after the plugin has been initialized, or if you want to provide a manual option to refresh the page (in case prices have changed or something).
My use case is as defined by Apple: Either adding a new device or restoring a device that was wiped out.
My app acts just like the statement is not valid as execution does not run in that function call.
Can you verify what the calling procedure would look like in Javascript? Maybe I have something wrong in the calling statement.
You should do CdvPurchase.store.restorePurchases()
- (store.restorePurchases()
is a shortcut if you're storing "store" in the global namespace). Could it be this?
Well the good news is that I just swapped update() for restorePurchases() in my function and it did not break there. But I cannot test it yet because I need to get over problem #1389
Once that is complete I can test the entire process.
update()
on the other hand is a lightweight method that'll re-validate the application receipt (still on iOS), if you have a receipt validation service in place. It will refresh the user's purchases.
@j3k0 This is still true on v13.3.11 for iOS, right? I cannot find a way to revalidate the receipt when I want to (e.g when the logged-in user changes). I have tried with update() and restorePurchases() and neither seems to call my custom validator after a previous successful validation. (I'm using an auto-renewable subscription)
All is working fine on Android with update().
@lafbarroso Still true. You could try this to force re-validation of the receipt on iOS:
CdvPurchase.store.localReceipts[0].verify();
@j3k0 , I know you have closed this task, but I have a question. Since the API return Promise<void>
what happens if a user taps on this button and
Case 1: They had previously purchased and changed phone Case 2: They had not previously purchased
How can I separate out between 2 situations given this API return method. Currently, I call following method if a user taps on the "Restore purchase" button
const restorePurchase = async () => {
store.restorePurchases().then(() => {
console.log(`purchases restored`)
// assume user had purchased previously update db to make user premium
// but if this assumption is wrong, every free user can become premium user without paying
}).catch(e => console.error(`failed to restore purchases`))
}
I am sure I am missing something fundamental here and need your help in understanding. Kindly guide.
The promise is resolved once the local receipt has been refreshed. In any case, "update DB" should happen in your store.when().approved(...)
handler. This way you will include all cases: restored purchases, pending transactions processed at startup, live purchases, family shared purchases, etc.
This promise is just to show/hide your loading indicator.
Thanks, so you mean, do something like this
store.when()
.approved((transaction) =>{
transaction.verify()
// check transaction.products to ensure product id matches and update DB, make user premium
})
The above code happens when user opens the app. Is that correct?
Also, I am wondering about when user hits the "Restore Purchase" button. There could be 2 users
How do I ensure that only UserPremium is upgraded, but not UserFreemium? Could you please guide?
I updated my code to following based on your guidance
store.when()
.approved((transaction) => handleApprovedTransaction(transaction))
where handleApprovedTransaction()
is
const handleApprovedTransaction = async (transaction: CdvPurchase.Transaction) => {
await transaction.verify()
const alreadyPurchased = transaction.purchaseId !== undefined &&
transaction.products.filter(p => p.id === productId)[0] !== undefined
if (alreadyPurchased) {
console.log(`user has already purchased ${productId}, upgrading to premium`)
await updateUserStatus()
}
}
I believe this handles the recommendation you have. However, my question still remains about when user clicks on "Restore Purchase" button.
I want to ensure that only UserPremium is upgraded and not UserFreemium. Otherwise, every iOS user who taps on this button becomes premium user without paying :-)
Hello.
Can you explain how the 'restorePurchases' method should work on Android when called without any valid 'restorable' purchase? I don't see any event handler called in that case despite native Java code returning an empty purchases array:
sendToListener() -> setPurchases data -> {"purchases":[]}
Using version 13.6.0
I have upgraded my app from V9.x to 13.3 and finally gotten everything working but the iOS refresh purchases. I had a custom Restore Purchase routine before that forced a verify on my three subscriptions and then called store.refreh() to complete it. It worked fine. But of course store.refresh() is no longer available and the docs say in this instance to use CdvPurchase.store.restorePurchases().
But this call stops my app from functioning in the routine it is called in. I was expecting it to do something similar to store.update.
Should I just use store.update() and is there any value in calling the verify on each of my products before?