I would like to know if the in-app billing api needs to have internet access when checking if the user have purchased an item or not.
I want to sell game levels using the in-app billing but don't want to access the internet everytime the user starts playing the level.
Does market have any cache mechanism to avoid calling the server everytime? Do I need to implement it on my app?
There are two types of purchases. Managed and unmanaged. Managed products can only be bought once, however unmanaged products can be bought any number of times.
There is no caching as such by the market app. Say for example, you have a managed product ID setup, and you a user has already bought it. The next time you request the market app to buy the same item, it will return with a response, saying "already purchased".
In case of unmanaged items, it just carries out the transaction.
In both the cases, internet is required.
It's upto you how you save the transactions locally, and initiate a purchase by checking if you really need to do another purchase.
You don't even need the Internet permission to use in-app billing. Market will take care of that for you.
Related
We are facing with some sort of interesting scenario. On one of our production apps, a user came to us that they've bought the app before and even then, they cannot use the premium features.
In our app, we used IAP (Google Play Billing library, not IABHelper) with one-time product method: We let the user buy the app, and then never consumed the product. The method we're following is: After reading some questions here and examining documentation, I've found out that BillingClient.queryPurchases(INAPP) scans the purchases locally and any inactive products are not there, and due to them being not there, if premium features are active, we're disabled it.
BillingClient.queryPurchaseHistoryAsync(INAPP, listener) returns all products whether they are active or not, but the product is not a subscription so Purchase.isAutoRenewing() is always false.
Here is the problem: If we wipe out Google Play's data or reset the phone and download the app again, since the data in Google Play is deleted, BillingClient.queryPurchases(INAPP) returns an empty list, even if the user bought the app before. In this scenario, BillingClient.queryPurchaseHistoryAsync(INAPP, listener) method seems to be useful but, it does not contain any information about whether the product is active or refunded.
Final case is, we need to consume the product if it is refunded to close premium features (or activate them since there is no local information) but there is no data that the product is bought and fetching data from API itself with queryPurchaseHistoryAsync does not contain any information about the product is active or not, it's just there, represents that it has been bought before. So how should we know if somebody bought this product and not get a refund?
I have an Android app where users can buy 1 inapp product to unlock some features.
I've read extensively the guide at: https://developer.android.com/google/play/billing/billing_library_overview#java
I understand that in order to let users buy the inapp product I have to:
Retrieve the list of available SKUs (in this case, my only 1 inapp product) using the querySkuDetailsAsync() call. This is just to double check the user's device is capable of managing inapp products.
Show the BUY button if the SKU appears in the result of the previous call (which means the local Google Play instance in the user's device can handle inapp products).
Call launchBillingFlow() passing the SKU of my inapp product, to initiate the Google payment process flow (Google UI, popup asking for card details etc..)
Listen to the callback onPurchasesUpdated() to get the return code (basically payment denied, payment successful or payment cancelled) and act accordingly. In case of payment successful proceed to verify the purchase token signature either locally (using a local copy of the Play developer's RSA public key) or remotely on my secure server with the same key.
unlock the paid features(s) on my app
That's where things get confusing. From the Google documentation perspective the job is done, they explained to you how to retrieve/purchase/and verify a user payment. However, nowhere it is explained how to remember the payment and unlock the paid feature during the app startup.
The documentation states:
To retrieve information about purchases that a user makes from your
app, call the queryPurchases()
So it seems like the app doesn't need to remember anything, just call the queryPurchases() at startup and check if the SKU is present (user already paid for it) or not (user still hasn't bought the paid version of the app).
So my app is doing just that, calling queryPurchases() at startup and check if the SKU is present or not.
This method works very well, even when the app starts offline. However some users are lamenting the fact that sometimes the app doesn't start in paid mode, because (I debugged the code) the function queryPurchases() fails (sometimes) when the device is offline. Could it be that the queryPurchases() is calling the local Google Play cache which can lose track of previous purchases for some reason? (cache purging, etc...)
What's the appropriate method to remember user purchases and enable paid features at app startup?
You could keep your own "cache" (SharedPreferences or a DB) with the results of onPurchasesUpdated and use queryPurchaseHistoryAsync. When the app first starts you can show paid content if your cache is telling that the user purchased the product and call queryPurchaseHistoryAsync at the same time to get the most recent purchase made by the user for each SKU, when onPurchaseHistoryResponse you can update your cache and hide the paid content if the purchase expired.
Take also into account that it's recommended for security purposes to go through purchases verification on your backend.
If you don't want to manage your own server, it may be worth using a tool like RevenueCat, that offers a purchase/subscription backend-as-a-service.
How often does it happen? My take is that Google Play client is taking care of caching, so there is no direct way how to handle that if you are just relying on this service. This can cause troubles if users re-install or change their devices.
Another approach is to build your own back-end, which will be necessary if you want to grow your app anyway.
I'm trying to implement in-app billing system in my app to serve ads free version to users. I learned these steps and finally I succeeded to buy my product by using my test account. (I got the OK resposeCode through onPurchasesUpdated() method.)
However I could not buy it again. There was no response after calling launchBillingFlow(). I don't know why. Even if my product is ads free version (I mean permanent item.), I want to know that buying one item several times. Please let me know.
Once a managed product is purchased, it is considered to be "owned".
Managed products in the "owned" state cannot be purchased from Google
Play. You must send a consumption request for the "owned" managed
product before Google Play makes it available for purchase again.
Consuming the managed product reverts it to the "unowned" state, and
discards the previous purchase data
As soon as the User buys a product from your application, just consume it and keep track of the purchase some other way. By storing the credits on your server may be.
More on the developer site
Just be sure to call mBillingClient.endConnection() before calling mBillingClient.startConnection() again.
If you don't call endConnection() onPurchaseUpdated() will be called for every connection that is not closed.
In my case I call mBillingClient.endConnection() inside onDestroy() method of my activity.
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 have working app that sells in-app products (InApp billing v3).
Recently I've made an update for this app and made a terrible mistake there: I consumed some of purchases I didn't want to consume.
I issued an update and users updated the app and then wrote me they have no purchased access. (As I found later, I consumed wrong items).
So I have some questions now:
Is there a way to restore consumed purchases or I should return payments to my users?
Is there a way to find out how many and which purchases were consumed?
If returning payments, is there a way to find out if user still has the product or is it consumed with out changing the app (through google services)?
Thanks.
According to what I have understood from your question, It seems like you want to purchase product only once.
What I wished to ask: is there a way to request information about consumed products like about owned products.
you can get response or it's information in any type(Managed Product, Unmanaged Product, Subscription) in the onActivityResult method() check my below link.
In-app billing-v3 error in activity result
but I would not prefer you to manage it customly as you told for one time purchase product(not consumable product). You should go with the Manage product.
Managed In-app Products:
Managed in-app products are items that have their ownership
information tracked and managed by Google Play. When a user purchases
a managed in-app item, Google Play stores the purchase information for
each item on a per-user basis. This enables you to later query Google
Play at any time to restore the state of the items a specific user has
purchased. This information is persistent on the Google Play servers
even if the user uninstalls the application or if they change devices.
for more information about product type
you can query any time you want and you will get the product information, and even you don't need to manage if user has already purchase this product or not.
Is there a way to restore cnsumed purchases or I should return payments to my users?
Better option is you should give the payments back to the user and for the next time check the whole app once using dummy product "android.test.purchased" and update your app.
Is there a wat to find out how many and which purchases were consumed?
You have to check in the Google wallet because all transaction should be handle by the it, check if it gives you product type or not. Using your google developer console credential you can signed into google wallet.
If returning payments is there a way to find out if user stil has the product or is it consumed with out changing the app (through google services)?
as per above answer you have to check in google wallet, according to my knowledge they are provide us all of information about product type with user detail.
Let me know if I have not properly understood your question.
Hope it will solve your problem.