Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

store.when().approved() is triggered each time on app launch #1428

Closed
kurtiev opened this issue Jun 15, 2023 · 10 comments
Closed

store.when().approved() is triggered each time on app launch #1428

kurtiev opened this issue Jun 15, 2023 · 10 comments

Comments

@kurtiev
Copy link
Contributor

kurtiev commented Jun 15, 2023

While testing payments on Android, it's scheduled in 5 minutes to cancel a purchase, and during this 5 minutes, I'm getting triggered .approve() callback each time when the app launched.
Why so?
And it's will be triggered each time for production as well?

 const {store} = CdvPurchase;
 
   store.when()
      .approved((transaction) => {
        alert('approved'); // triggered each time on when app launched, until purchase is cancelled by PlayMarket
})

By the way, callback verified() never triggers:

const {store} = CdvPurchase;
    store.when()
      .approved((transaction) => {
        alert('approved');
        return transaction.verify();
      })
      .verified(async (r) => {
        alert('verified');
        return r.finish();
      });

UPDATES:

Started testing iOS on Testflight.
Really weird behavior, I just installed the app, and after launching it, continuously triggers approve() callback, with no reason. I didn't buy anything yet.
What is happening over there?

@kurtiev kurtiev changed the title store.when() is triggered each time on app launch store.when().approved() is triggered each time on app launch Jun 15, 2023
@TheNotorius0
Copy link

TheNotorius0 commented Jun 19, 2023

If you make a purchase but don't .finish() it, it's normal that at every app launch the when().approved code will be resumed.

This is useful for example if you have promotional codes, so they enter them in Google Play, then enter the app, and they can redeem the product (or you can make the user follow a few steps before calling the .finish() function). So you need to handle this in your code.

About the when().verified not working, you need to seup a validator, for example:

store.validator = https://validator.iaptic.com/v3/validate?appName=com.azmar2.sevangames&apiKey=xxxxxxxxxxxxxxxx;

If you don't define a store validator, you can't use the verify function, it just doesn't work.

HOWEVER

I released my APP on Apple Store, and I'm experiencing the exact same bug as yours. A friend just installed the app, and he is telling me that when he opens the app, it continuously triggers the verify() callback (in my app it also displays a "waiting" popup, so it's unusable).

Of course he didn't buy anything either, and I have logs that it happens to every iOS user. Unfortunately, I don't have an iPhone and the emulator doesn't support in-app purchases, so I can't test it properly.

I don't know if it's related to this #1269

@kurtiev
Copy link
Contributor Author

kurtiev commented Jun 20, 2023

Maybe version 13 is not ready for production yet, @j3k0?
In the documentation, it says "v11.0 is MAIN"

image

But v11.0 uses com.android.billingclient:billing:4.0, which will be deprecated in 2nd August
image

@j3k0
Copy link
Owner

j3k0 commented Jun 20, 2023

v13 is ready and used in production. The "gitbook" default hasn't been updated. We'll fix that.

@TheNotorius0
Copy link

So, as I've said, it's normal that at every app launch the when().approved code will be resumed if the transaction isn't finished. You can handle it in your code.

About this problem:

UPDATES:

Started testing iOS on Testflight. Really weird behavior, I just installed the app, and after launching it, continuously triggers approve() callback, with no reason. I didn't buy anything yet. What is happening over there?

I've just tested it with StoreKit. Apparently (I don't know if it's by design) in iOS, you get an "approved" callback the first time you initialize in-app-purchases, with your bundle ID as product id. Just add this code to catch it / prevent it from doing anything, and you will fix your problem:

store.when().approved((transaction) => {

    if (transaction.products && transaction.products[0] && transaction.products[0].id === 'robotchef.cooking.recipes') {

        transaction.finish();
        return;
    }

    if (transaction.state === 'approved') {

        transaction.verify();
    }
});

@Dexus
Copy link
Collaborator

Dexus commented Jun 30, 2023

I've just tested it with StoreKit. Apparently (I don't know if it's by design) in iOS, you get an "approved" callback the first time you initialize in-app-purchases, with your bundle ID as product id. Just add this code to catch it / prevent it from doing anything, and you will fix your problem:

store.when().approved((transaction) => {

    if (transaction.products && transaction.products[0] && transaction.products[0].id === 'robotchef.cooking.recipes') {

        transaction.finish();
        return;
    }

    if (transaction.state === 'approved') {

        transaction.verify();
    }
});

That is normal, the iOS app is bought as you buying everything even it is free at apple.

@nadeeth
Copy link

nadeeth commented Aug 9, 2023

Recently we upgraded the plugin from v11.0.0 to the v13.6.0.

In app purchases worked fine while we were testing the iOS version in Test Flight. But after the production publish, we found this issue is happening in the production version of our iOS app. In the production app, the In App Purchase is always approving for all the users when the app is starting. So now, the product is enabled for all the iOS users of the new app version including the users who haven't purchased the product. We have paused the phased rollout for now, but around one fourth of the iOS user base has got the update already.

I am considering to move back to the old plugin version and do an iOS only release as a temporary solution. In our case, this is happening only in the App Store version of the iOS app, so we didn't know about it before publishing. And also, I noticed, Product.owned always returns false in iOS (even when the users has purchased the product).

We are using the plugin with Capacitor 5.

@cmaas
Copy link

cmaas commented Sep 20, 2023

I encountered the same thing on iOS. Before in v11, when I started the app, the approved() handler only triggered if there were unconsumed transactions. Now in v13, approved() triggers with every app launch.

However, there's a difference that I overlooked at first:
v11 code:

.when(productId)
  .approved(finishPurchase)

v13 code:

.when()
  .approved(finishPurchase)

v11 filtered all incoming based on the productId, whereas the v13 handler does not filter. Hence, on every app start on iOS, you receive a transaction with the transactionId appstore.application (see APPLICATION_VIRTUAL_TRANSACTION_ID here:

export const APPLICATION_VIRTUAL_TRANSACTION_ID = 'appstore.application';
) or productId = your bundle.

Hence, you need to filter in your handler based on existing (real) product ids. But I haven't tried it in production yet.

@TheNotorius0 gave a hint, but I didn't understand why this didn't happen before in v11. The filtering seems to be the difference. But I think you don't need to call .finish() on your bundle ID transaction, because it apparently doesn't seem to be finished ever and will always trigger again.

@gizmodus
Copy link

I also noticed that the approved() callback is called even if no purchase was made. What is the purpose of transactions with an id appstore.application mean? Is it a safe discriminator to distinguish fake from real (new) transactions?

@cmaas
Copy link

cmaas commented Sep 22, 2023

I also noticed that the approved() callback is called even if no purchase was made. What is the purpose of transactions with an id appstore.application mean? Is it a safe discriminator to distinguish fake from real (new) transactions?

It just means that you "bought" the (free) app. The app itself is considered a transaction. If you install an app from the App Store, you are asked for your password and if you really want to "purchase" the app, even if it's free. For some reason, this transaction shows up all the time.

@gizmodus
Copy link

@cmaas Thank you very much for the clarification! Makes sense.

@j3k0 j3k0 closed this as completed Sep 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants