cordova-plugin-inapppurchase icon indicating copy to clipboard operation
cordova-plugin-inapppurchase copied to clipboard

Check if product was purchased (thin client/no server)

Open lifzgreat opened this issue 9 years ago • 37 comments

Hi! First of all..thanks SO much for this awesome plugin.

What is the best way to determine if a product was already purchased? This is a "thin" app, there is no back-end server. The only product is a simple "buy the dev a cold one" to get rid of ads. Is the best way to just store the purchase in localStorage() or should it call restorePurchases() every time the app starts? That seems a bit excessive though.

Thanks again!

lifzgreat avatar Jun 24 '16 02:06 lifzgreat

@lifzgreat Use receipt validation to solve your issue.

mitiaptest avatar Jun 27 '16 15:06 mitiaptest

there is no back-end server

@mitiaptest I was under the impression I needed a back-end server to do that. Is that incorrect?

lifzgreat avatar Jun 27 '16 15:06 lifzgreat

@lifzgreat Not required.

mitiaptest avatar Jun 29 '16 11:06 mitiaptest

Hmm, I guess I'm not following. Would we validate (this term is still a bit "fuzzy" to me) every time the user logs into the app?

lifzgreat avatar Jul 01 '16 00:07 lifzgreat

Util now, i don't how to check user have purchased. Can anyone help me? Maybe, using localStorage save transaction id. Is that right?

nhiendat avatar Oct 06 '16 14:10 nhiendat

@lifzgreat set interval and validate your users receipts.

mitiaptest avatar Oct 06 '16 14:10 mitiaptest

@mitiaptest, could you explain detail for your said "Use receipt validation", pls? Thank you :)

nhiendat avatar Oct 06 '16 14:10 nhiendat

server is necessary to do receipt validation

mitiaptest avatar Oct 06 '16 14:10 mitiaptest

@mitiaptest, Thank for your reply. I don't use server. That is problem of this issue. Do you any suggesst?

nhiendat avatar Oct 06 '16 14:10 nhiendat

@nhiendat I will try to help you since others are not very helpful at all. I had to make my way through it with no help too :) What I ended up doing was storing the purchase in localStorage. I then provided a button to restore purchases in case localStorage was somehow erased. That doesn't require a server and lets the user restore purchases if he needs to :)

lifzgreat avatar Oct 06 '16 14:10 lifzgreat

@lifzgreat , "restore purchases in case localStorage was somehow erased." that mean end user must repurchase -> It will make uncomfortable to end user. This is final solution. Right?

nhiendat avatar Oct 06 '16 14:10 nhiendat

@nhiendat If localStorage gets erased, the user will just click "restore purchases" which restores purchases without the user actually buying them again. There's no pain for the user :) And that is only necessary if the localStorage gets erased (manually by the user, or reinstall, things like that).

lifzgreat avatar Oct 06 '16 15:10 lifzgreat

You right, i am clear. But how do you differentiate end user not buy yet and localStorage gets erased. Both cases localStorage is empty (eg: localstorage.getItem('receipt') == null) ?

nhiendat avatar Oct 06 '16 15:10 nhiendat

The plugin handles that. When they click "restore purchases", you need to run the inAppPurchase.restorePurchases() function. Here is what I have:

   restorePurchases = function() {
     inAppPurchase
       .restorePurchases()
       .then(function(purchases) {
         if (!purchases.length) {
           alert("Sorry, there's nothing to restore. You haven't purchased anything using this account before!");
         } else {
           // Store the purchase in localStorage
         }
       })
       .catch(function(err) {
         alert("Error restoring purchase: " + err.message + " (Code " + err.code + ").");
       });
   };

lifzgreat avatar Oct 06 '16 15:10 lifzgreat

Great, thank a lot @lifzgreat . I am clear now. I can explain i understand as bellow: If localStorage empty then run restorePurchases() function Continue, If response available then save transaction data into localStorage Else run buy() function and save transaction data into localStorage if buy successful

nhiendat avatar Oct 06 '16 15:10 nhiendat

No problem!

Well, I don't automatically run the restorePurchases() function. I only run it when the user clicks the restore button (for example, he installs on a new device, he can transfer his purchase to that new device). But if they decided to NOT purchase in the first place, I don't run the buy() function for them without them running it themselves :)

lifzgreat avatar Oct 06 '16 15:10 lifzgreat

I run automatically the restorePurchases() function to check purchased but unsuccessful (result is always show ads item after re-run application). I don't know reason. My code as bellow:

// Default show ads
$scope.isShowAds = true;

if(window.inAppPurchase){
    inAppPurchase.getProducts(['product.ads']).then(function(products){
        // Check product
        if(products[0].productId == 'product.ads'){
            // Check user purchased
            inAppPurchase.restorePurchases().then(function(data){
                if(data.productId == 'product.ads'){
                    $scope.isShowAds = false;
                    AdMob.removeBanner();
                }else
                {
                    $scope.isShowAds = true;
                    showAds();
                }
            }).catch(function(error){
                console.log(error);
            });
        }
        else{
            $scope.isShowAds = true;
            showAds();
        }
    }).catch(function(error){
        console.log(error);
    });
}
else{
    console.log("NO PLUGIN IN-APP PURCHASE");
}

// Remove Ads click function
$scope.removeAds = function(){
    inAppPurchase.buy('product.ads')
        .then(function(data){
            if(data.productId == 'product.ads'){
                $scope.isShowAds = false;
                AdMob.removeBanner();
            }
            else{
                $scope.isShowAds = true;
                showAds();
            }
            // This line required for Android purchases, does not affect iOS purchases
            return inAppPurchase.consume(data.type, data.receipt, data.signature);
        })
        .catch(function(error){
        console.log(error);
    });
};

Do you know my mistake?

nhiendat avatar Oct 06 '16 15:10 nhiendat

Hard to tell without having it in front of me but I'd start by checking all of your if() statements and making sure they're being hit like you think they should!

lifzgreat avatar Oct 06 '16 16:10 lifzgreat

Thank for checking @lifzgreat , I think if i use restorePurchases() function then unnecessary using localStorage. Right?

nhiendat avatar Oct 06 '16 16:10 nhiendat

Right, the only reason I use localStorage is so I don't have to run restorePurchases() every time the app runs :) If the purchase is in localStorage, there's no need to run it. If it's not, then the user can run it if he starts getting ads.

lifzgreat avatar Oct 06 '16 17:10 lifzgreat

Yeah. I try to test my code above following:

  1. After click button 'Buy' to purchase then hide ads, hide button 'Buy'
  2. Close and open app again but show button 'Buy' again.
  3. Try click button 'Buy' again then result as step 1. This step It must show message: 'already purchased' (don't remember exactly content of message) Do you see that something unreasonable?

nhiendat avatar Oct 06 '16 17:10 nhiendat

Hmm, nothing jumps out at me right away but I would go through each if() and do alert() something to make sure it's doing what you think it should. There's something about buying/restoring every time that might not work...might HAVE to use localStorage but I'm not sure...sorry I'm not more help!

lifzgreat avatar Oct 06 '16 17:10 lifzgreat

Thank for your support. I will try debug with alert. So, i just used localStorage to avoid call restorePurchases() function when app start. Have a nice day :)

nhiendat avatar Oct 06 '16 17:10 nhiendat

That's what I did too, seems to work great :)

And no problem!

lifzgreat avatar Oct 06 '16 17:10 lifzgreat

@ lifzgreat

Hi, Where you able to resolve your issue?

Waiting for your reply.

Regards, Venkat

Venkat-TTapp avatar Dec 19 '16 17:12 Venkat-TTapp

Hi @Venkat-TTapp, if you read over the thread, you will see that I did and gave code as well.

lifzgreat avatar Dec 19 '16 17:12 lifzgreat

Yeah.. re-read whole thread again.. sorry about it...

I need help pertaining to restore purchase.

I did a test integration and the plugin works perfectly well, but I am getting struck at restore purchase.

When I do a restore purchase (Without doing a purchase), I am getting empty result "[]" in console.log. and no error because of which this restore purchase check turns out to be a sucess.

Below is the code what I have used:

function Restore_purchase(){
inAppPurchase
.restorePurchases()
.then(function (purchases) {

    console.log(purchases);
	console.log(JSON.stringify(purchases)); 
	alert(JSON.stringify(purchases));
   
  alert("restore purchase success");
  })
  .catch(function (err) {
    console.log(err);
	
	console.log(JSON.stringify(err));
	alert(JSON.stringify(err));
	
	alert("Restore purchase error");
  });

Regards, Venkat

Venkat-TTapp avatar Dec 19 '16 17:12 Venkat-TTapp

@Venkat-TTapp ok check up a few comments to where I posted the code I used to do this. You have to check purchases for length. If it's empty, they haven't purchased anything - simple as that :)

It is line 5 in this comment above: https://github.com/AlexDisler/cordova-plugin-inapppurchase/issues/44#issuecomment-251997440

lifzgreat avatar Dec 19 '16 17:12 lifzgreat

@ lifzgreat, Thanks, #44 (comment) resolved this scenario.

I have 3 non consumable product in my app, I am not sure how restore purchase would behave where there is more than 1 purchase (Not sure how to pick and show which product to restore), I will do a test purchase and try to do a purchase restore. If I am struck, I will seek your help.

Thanks for your time,reply and support,

Regards, Venkat

Venkat-TTapp avatar Dec 19 '16 18:12 Venkat-TTapp

@Venkat-TTapp well you just loop through all purchased products and modify your app depending on what was purchased. For example, let's say you have 2 products,: 1-kill ads, and 2-open levels. When you run restore purchases, anything that has been purchased before will be returned. Simply check the item and modify your app depending on which one(s) come(s) back. A very simple example:

for (i in purchases) {
    if (purchases[i].productId == "killAds") {
        killAds();
    } else if (purchaes[i].productId == "unlockLevels") {
        unlockLevels();
    }
}

The productId is whatever you made it when you created it in the Google Dev console.

lifzgreat avatar Dec 19 '16 18:12 lifzgreat