j3k0 / cordova-plugin-purchase

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

How to detect active subscription when visiting subscription page #1501

Closed scattered closed 5 months ago

scattered commented 6 months ago

I'm using cordova-plugin-purchase version 13.8.6 and fovea.cc within my Ionic application.

When a user navigates to the subscription page I want to put a green checkmark next to the active subscription to indicate that which subscription they have (1 month, 3 month or 12 month).

When the page loads I perform the following:

CdvPurchase.store.minTimeBetweenUpdates = 1000; // For testing purposes only
CdvPurchase.store.verbosity = CdvPurchase.LogLevel.DEBUG; // For testing purposes only

CdvPurchase.store.register([PRODUCTS ARRAY]);

CdvPurchase.store.error(err => { console.error(err) });
CdvPurchase.store.ready(()=> {
  CdvPurchase.store.update().then(() => {
    console.log(CdvPurchase.store.verifiedPurchases) // Always an empty array
    console.log(CdvPurchase.store.owned('sub_1_month')) // Always false
    console.log(CdvPurchase.store.owned('sub_3_month')) // Always false
    console.log(CdvPurchase.store.owned('sub_12_month')) // Always false
  });
});

CdvPurchase.store.when().receiptUpdated(receipt  => { receipt.verify() });
CdvPurchase.store.when().productUpdated(product  => {
  console.log(product.owned) // Always false
});
CdvPurchase.store.when().approved(transaction  => { transaction.verify() });
CdvPurchase.store.when().verified(receipt  => { receipt.finish() });
CdvPurchase.store.when().finished(transaction  => {
  // Update UI after purchase
});

CdvPurchase.store.initialize();

As you can see form the above, calling owned is always false and verifiedPurchases is always an empty array.

How can I detect if a subscription is active?

Note: I can see the webhooks being executed in the fovea.cc dashboard and being received and processed on my server. I can also detect if the user has an active subscription on the server by looking at the data I save from the fovea.cc webhook which includes the UTC expiry date. However, I would assume that I can retrieve the information from within the plugin so I don't need to do another server request.

Note: I'm using sandbox accounts to test the purchases

Note: I'm testing on real iOS and Android devices.

j3k0 commented 5 months ago

Note that it is incorrect to call "update()" after the "ready()" event.

CdvPurchase.store.ready(()=> {
  CdvPurchase.store.update().then(() => {
    console.log(CdvPurchase.store.verifiedPurchases) // Always an empty array
    console.log(CdvPurchase.store.owned('sub_1_month')) // Always false
    console.log(CdvPurchase.store.owned('sub_3_month')) // Always false
    console.log(CdvPurchase.store.owned('sub_12_month')) // Always false
  });
});

The below is also incorrect:

CdvPurchase.store.when().receiptUpdated(receipt  => { receipt.verify() });

You should only verify approved transactions.


CdvPurchase.store.when().productUpdated(product  => {
  console.log(product.owned) // Always false
});

"productUpdated" is ony called when the product's metadata are updated (pricing, title, ...)

So you won't get a call to productUpdated after receipt validation. The right place to check for ownership, when using a receipt validation service, is generally the "verified()" and "unverified()" handlers.


I advise you switch from fovea.cc to https://iaptic.com -- just replace "fovea.cc" by "iaptic.com" in the validator URL and it will work right away: cf https://www.iaptic.com/documentation/information-fovea-billing


I also advise you check the example for an example implementation of subscription: https://github.com/j3k0/cordova-subscription-example -- the "with-server" example will apply to your case.

alb99 commented 5 months ago

I have the same problem product.owned is always false. Test on IOS. I switched from version 11 to 13. The validation runs via my own server. There were no problems. I have tried to stick to the "with-server" example. Which call could still be missing to set product.owned?

My validation response json:

{ ok: true, status: 'valid', data: { product_id: purchase.productId, quantity: 1, transaction_id: purchase.transactionId, purchase_date: purchase.purchaseDate, expiration_date: purchase.expiresDate || purchase.expirationDate, "is_canceled": false, "is_refunded": false, id: purchase.productId, latest_receipt: true, transaction: _transaction } }

The subscription is active in the device. (Store subscription overview) Even after I restarted the app, "owned" is still false.

j3k0 commented 5 months ago

Make sure the collection field is filled by the receipt validator. This is how "owned" products are sent by the server to the plugin.