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

Load local receipt at startup to see my owned products are #1529

Open reinos opened 2 months ago

reinos commented 2 months ago

It seems that after I made a purchase and restart the app it will not load my receipt and the transactions. Only the call store.restorePurchases() will fix that. But from what I read in the issues this call should be avoided as the transactions should be loaded at startup.

As stated here https://github.com/j3k0/cordova-plugin-purchase/wiki/HOWTO:-Migrate-to-v13#product-ownership the receipt is loaded, but it seems not in my case.

So my question here is, why it is not loaded my purchased subscriptions and only load them when I call store.restorePurchases()

My code:

 const productIds = ['starter_month'];
  for (const id of productIds) {
    store.register({
      id,
      type: ProductType.PAID_SUBSCRIPTION,
      platform: Platform.APPLE_APPSTORE,
    });
  }

  store
    .when()
    .productUpdated(() => {
      const fetchedProduct = store.get('starter_month', Platform.APPLE_APPSTORE);
      console.log(fetchedProduct.owned);
      console.log(store.verifiedReceipts);
      console.log(store.localReceipts);
    })
    .approved(transaction => {
      if (transaction.products.find(product => productIds.includes(product.id))) {
        console.log('approved', transaction);
        return transaction.verify();
      }
    })
    .receiptsReady(receipts => {
      console.log('receiptsReady', receipts);
      console.log(store.verifiedReceipts);
      console.log(store.localReceipts);
    })
    .receiptUpdated(localReceipt => {
      console.log('receiptUpdated', localReceipt);
      for (const productId of productIds) {
        if (store.owned(productId)) {
          console.log(`VIA productIds: ${productId} is owned`);
        }
      }
      console.log(store.verifiedReceipts);
      console.log(store.localReceipts);
    });

  store.initialize([Platform.APPLE_APPSTORE]).then(() => {
    store.restorePurchases().then(async error => {
      console.log(error);
    });
    // console.log(CdvPurchase.store.ref);
  });
};
brandon-lile commented 1 month ago

I'm noticing a similar issue. This happens both with/without using a custom validator. If the validator is removed, and validation is done only on the device, the store.owned(product) call never returns true for any auto renewable subscription.

The docs also show an example set of code to check for owned products, and it also never returns true for any product, even if it is successfully purchased.

Example code:

        store.when().receiptUpdated(localReceipt => {
            localReceipt.transactions.forEach(transaction => {
                transaction.products.forEach(product => {
                    if (store.owned(product)) {
                        console.log('You own product: ' + product.id);
                    }
                });
            });
        });

I'm happy to help get this resolved, whatever way I can, but it does appear to be an issue on version 13.10.1

veronicatc commented 2 weeks ago

I am experiencing the same issue. I am using iOS and testing on Sandbox, purchasing an auto-renewable subscription.

The receipt that gets loaded at startup, only has one transaction which is for the app itself, the transaction with ID appstore.application. But it does not have any transaction for the subscription itself.

If I call store.restorePurchases() afterwards, the transactions show up.

If the subscription happens to be automatically renewed when the app is open (every 5 minutes with apple sandbox monthly), the app also recognizes this ok and verifies it ok.

But if I close the app, and open it again, the app receipt will only have the transaction with ID appstore.application.

I had not noticed this with version 11, could be because the old store.refresh() called restorePurchases?

bigreni commented 2 weeks ago

I have the same problem. When I do a store.get(productId, CdvPurchase.Platform.APPLE_APPSTORE) and check if the user owns the product - product.owned is never set for the auto renewing subscription. It works fine on Android.

veronicatc commented 2 weeks ago

I have tried something that worked. The receipt was there. It was just not listing the right transactions. So I added a call to receipt.verify() inside the store.when().receiptUpdated callback. It is very important to only call receipt.verify() the first time this callback is hit, keep track that it has been done and not call it again in subsequent calls, or you get in a loop. I also added the call only if the receipt is listing one transaction which would be the appstore transaction, this last step I did because I am not sure if the issue happens only in sandbox, and maybe in production the receipt does have the transactions initially.

       iapInitialReceiptUpdated=false;
       store.when().receiptUpdated(receipt => {
            if(!iapInitialReceiptUpdated){
                if(receipt.transactions.length == 1){
                    receipt.verify();
                }
                iapInitialReceiptUpdated=true;
            }
        });