When my app queries whether it has an in-app product using IabHelper, if there is no connectivity the response I get is:
Error refreshing inventory (querying prices of items). (response: 6:Error)
And that's fine. But when my app tries to purchase an already owned item (still with no connectivity), Google Play returns that the user already has the item in question.
So, since Google Play knows whether a user has an in-app product or not regardless of there being a connection present, how do I get this information without trying to purchase the in-app product? I would like my app to know if it has an in-app product even if there is no connectivity and querying inventory fails, and the only way I know to get this information now is to try to purchase the product.
First. Drop using iabhelper, it is for your own good.
Second. Google Play Services caches information, so sometimes you get responses when device is offline. How and when this happens depends on current services implementation (which can and will change!). Make no assumptions and work with data as returned, offline or not.
Related
I have users that have purchased items (SkuType.INAPP) from my application.
In the previously recommended implementation of in app billing the IabHelper.QueryInventoryFinishedListener would return an Inventory that contained no items that they owned.
In the new Play Billing Library I use the following method:
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
Assuming the response code is successful, I query:
purchasesResult.getPurchasesList()
For this small percentage of users, the list is empty.
As a fail-safe, for negative results above, I continue to try:
mBillingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, this);
The onPurchaseHistoryResponse(final int responseCode, final List<Purchase> purchasesList)
successfully details the purchase.
Perplexed by this, I asked the affected users running both implementations to confirm the following:
They only had one Google account on the device
The one account received the purchase confirmation email
This is the only account option in the Google Play Store app
The Google Play Store app 'order history' detailed the purchase
Taking suggestions from this thread, I asked them to:
Clear data & cache from the Google Play Store app
Reboot
Log back into the Google Play Store
Open my app again
Despite the above, still, only queryPurchaseHistoryAsync correctly identified that their account owned items.
Question: Why?
The Billing Library implementation states:
queryPurchaseHistoryAsync() returns the most recent purchase made by
the user for each SKU, even if that purchase is expired, canceled, or
consumed. Use the queryPurchases() method whenever possible as it uses
the local cache, in preference to the queryPurchaseHistoryAsync()
method.
I have confirmed in my Order Management, that the purchases are valid and have not been cancelled. I do not consume them, therefore they cannot expire.
Now I have a problem
Given that for these users I can only identify their purchases in the above way, I am forced to implement this fail-safe for all.
Apart from being frustrated by the necessity of having to do this, it wouldn't seem like too much of a problem, until you read again:
queryPurchaseHistoryAsync() returns the most recent purchase made by
the user for each SKU, even if that purchase is expired, canceled, or
consumed
Therefore, in my standard implementation, I need to check that this purchase remains valid.
Unfortunately, the Purchase object has no such method to check its validity.
So, I probably need to perform an external check.
All when my app starts and my logic decides whether or not to show ads.
Help. Please.
i offer 1 in app purchase (full functionality). I save the result of the purchase in a boolean variable in sharedpreference and also use queryPurchases on app start, so if someone deleted and reinstalled the app, he gets his full functionality back.
That works properly, but i also would like to block full functionality, if it turns out, that someone did NOT purchase the full functionality (and cheated the app with a rooted device). That would also include deleting some data that he is not supposed to have without the in app purchase.
However, i am confused about the description of queryPurchases. It says
"Upon a successful purchase, Google Play's In-app Billing service caches the user's purchase data locally."
How long does it store that information? Does it update it automatically if an internet connection is available? How can i avoid getting no purchase even though the user bought the in app purchase and falsely blocking his full functionality? What is there
Is there a way to get the clear information, that the user in fact did NOT purchase a certain item, rather than just no information about a possible purchase? I really want to avoid blocking features if the user paid.
Anything else wrong with my approach (Saving the purchase in sharedpreferences
to have the information available immediatly and additionaly query purchase)
Edit: I also noticed, that if i refund an in app purchase, de- and reinstall the app, queryPurchases still finds that purchase. There must a way to avoid that?
Don't bother storing purchases in shared preferences. They are already on the device via the billing library. The purchases are stored in the Play store data which the billing library retrieves for you.
You can work by assuming that full functionality is enabled until you receive the result of query purchases which will tell you definitively whether the user has bought it or not. If you prefer, you can do that backwards and assume trial mode until you know a purchase exists.
Either way, the query for purchases will return quickly as no network connection is required because billing library simply connects to play store on the device for the data.
If you refund in the developer console, it may take a while for that to filter to the users device but it will eventually. It isn't a real time system and a purchase will remain cached on the device until the refund is fully processed and sent to the users device.
You can consume a purchase directly on a device which removes it instantly from the user account.
I've implemented API version 3 of GooglePlay Inapp purchase.
I'm logged in with the same Google account on two devices.
On device #1, I've just purchased an item using this: https://developer.android.com/google/play/billing/billing_integrate.html#Purchase
When I immediately query the purchased items (on device #1) with: https://developer.android.com/google/play/billing/billing_integrate.html#QueryPurchases it returns the info of the in-app so everything is fine.
When I query the list of purchases on device #2, it won't return the item I've just purchased, it returns an empty list.
When I try to buy the item on device #2 it tells me I already own it.
Any ideas on why the purchase from device #1 is not reflected on device #2 ?
Please note that the inapps are Managed products, so Google should hande the syncing across different devices with the same google account, right ?
Invalidating a purchase to test it again
This applies to products that the user can buy only once. This means that you don’t consume the purchase. More on consumption later.
In this case, after you make a purchase, if you will try to purchase it again you will receive an error saying that you already own this item.
How do you get past that?
You refund the purchase from Google Play Console. But there’s a catch. When you refund it you will have to remove the entitlement for that product, or the user will still get the error that it already owns the item.
For that, you go into Order Management from Google Play Console main menu and select the Order you just made from your app. (If it’s a test order it will say Test: in front of the product name). Then in order details, you click refund and a screen with some options for a refund like the one below will appear.
In this screen, make sure to check the Remove entitlement box, so the user will no longer own the product in his Google Account. After you click refund you will be able to make a purchase again for the given product.
It seems that it takes a while for the changed to actually take place on GooglePlay. The device on which I buy the item, seems to cache that I did so, and instead of asking GooglePlay, it takes that from a local cache.
That's why another device did not know about the purchase.
It took about an hour for the second device to receive the purchase info from GooglePlay.
I'm now developing a small game with Google's in-app billing service.
And I reference to Trivial Drive of Google's sample project.
Let's me ask you about connection interruption during Purchase Items from Google Play.
It's OK when launching purchase flow with normal internet connection.
I tested like this.
As soon as purchase flow is launched, disconnect the internet connection (by unplugging the routers' LAN).
After about 2-3 minutes, It shows Connection time out.
In merchant account, Money transfer is done.
But when I query All owned items, there is no owned item of this ID (purchased recently).
And when I try to purchase again this item, It shows "Error You already owned this item".
How can I solve this problem?
Anybody encountered like this problem?
Please Help. Appreciate to all comments and helps. Thanks.
The Google IAP flows requires you to call a consumePurchase() API after doing a purchase.
What you need to do is to call the getPurchases() API, this will return a list of purchases along with a purchaseToken. Then you need to iterate through them and call the consumePurchase() API for the purchased, unconsumed products.
For more reference, look at the API reference.
Is it possible to see what is available for purchase with the google in app purchase v3.
I have looked everywhere and I cannot get a hint of how to check if an item you want is available for purchase or not (e.g. I want to have a product in the app at a later time, and I check if I have added it to inapp purchases yet or not, without uploading a new app with those updates or a new database with those updates.
Is this possible, is there a way to query which items are available for purchase?
Not completely.
If you have the SKU code of your product, you can query its details using getSkuDetails(). However, you will need a list of the codes beforehand.