I am hosting a paid app. I have a query. How a person purchasing the app is recorded so as to when they need to re-download (say after wiping phone or refreshing the phone software) is the previous purchase recognised. Is there a registration or something that I would need to keep (or is it recommended).
If your app is downloadable from the Google play store then there is nothing you need to do. The play store will automatically work out when the user visits your apps page whether they need to purchase, whether they have purchased, or whether they purchased and then refunded.
The only thing you might want to do is to add some code at the start of your app launching that automatically checks google servers and ensures that the purchase has been made, otherwise you can block the app. Although this isn't fool proof but it highly reduces the changes of your app being pirated.
Related
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 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.
If i understood it correctly, both are storing information about inapp purchses somewhere outside the app.
https://developer.android.com/google/play/billing/billing_overview.html
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html#//apple_ref/doc/uid/TP40008267-CH8-SW9
I just want to make sure i've actually understood it correctly:
it is possible for user to reinstall app and get the features he has already paid for. And app does NOT need to have own server and remote database to be able to restore this data when user reinstalls it.
that is correct, you don't need to worry about payments, restore app. If user installs app on another phone or reinstalls app ( His/her in-app purchase flag is returned true based on his login id ). Handling in-app purchases flow within app is ours ( developers ) responsibility ( e.g. show additional flow , advance games level etc, virtual goodies within app. Needs to be taken care by developer ).
I do а premium upgrade of applications (ad free version), and use for this In app purchase v3 http://developer.android.com/google/play/billing/billing_integrate.html. Type of purchase is not controlled by Google. The main feature, I just did not consume the purchase, and a check make when you run the application, and advertising was removed. I`m testing this using the inAppid "android.test.purchased". But after some time (day, week, month) buying disappears and reappears advertising. Therefore, how to make a premium upgrade to be able to do the checking after purchase, without using your own server. SharedPreferences and SQLite are not suitable for this, because after you uninstall an application, data is lost, and purchase too. What type of purchase is better to choose, so that it is preserved for user forever. Need to make binding to Google Play account. Please advise how best to do so as it is very serious.
You are going to have to use your own server. The simplest option might be to use something like Firebase instead of writing your own server code & DB.
It is very strange that your purchase has disappeared after some time. Remember that test purchases will be cancelled by Google after 14 days.
If product was not consumed it will always restore and can't be purchased twice.
A good option is to have restore button somewhere in your app, forcing restore and providing feedback from any errors which may occur.
In my opinion you don't need a server or event local storage. Just check for purchase every launch
is that OK and safe to set a value in SharedPreference to flag that the user have purchased this item? What if user hack this value in SharedPreference. Or I need to connect IAP service everytime to check that before user can use it?
(1) What is the best practice when I use Google Android IAP V3?
(2) And also if user's device have no Google Play installed, I may want to use paypal to make the payment, but how to track the purchase and unlock the features for users if I ask user to use simple paypal payment to get a license key? I do not want to use any other billing SDK, if with Paypal web page to buy the license, How to implement this?
(1) What is the best practice when I use Google Android IAP V3?
--> official document says that only payment transaction will be handle by google play itself, but in the application you have to set your business logic how you handle UI integration and other things after product purchase. You can also go with the in app purchase v3.
(2) And also if user's device have no Google Play installed, I may want to use paypal to make the payment, but how to track the purchase and unlock the features for users if I ask user to use simple paypal payment to get a license key? I do not want to use any other billing SDK, if with Paypal web page to buy the license, How to implement this?
--> You can ask user to update google play version dynamically. Google developer doc says more than 90% device using 2.2 os with installed google play store. I could not say any thing about paypal transaction because I haven't use it before, but yes in app purchase using v3 is very simple to implement and understand the payment process.
How to use in your application
Three way to manage your application's product data.
1) SharedPrefrence:
you can use the share prefrence value and check whether it is purchased or not. if in case user uninstalled the app and then re-install the app then you can check whether user has purchased or not, at this you get the item is already purchased. And you have to manage the user to access your application data.
2) local database:
you can also use local sqlite database to store the purchase detail and purchase status. and same as above if user clear data or uninstall the app then request for the purchase item again and check whether user purchased item or not.
or
2) Server database:
It is the better way compare to above if you are using web server to store the user data. In this type, you doesn't even need to manage for the second time for the case if user uninstall the app or clear the application data.
3) obfuscation: (Most efficient way compare to shared prefrence)
EDIT:
is that OK and safe to set a value in SharedPreference to flag that the user have purchased this item? What if user hack this value in SharedPreference. Or I need to connect IAP service everytime to check that before user can use it?
While I am searching on internet I found Nikolay Elenkov's answer like below:
If you just save a flag in shared preferences, any user with a rooted
device can flip the flag at will and be 'subscribed' without paying.
So you should at least do some obfuscation. Here's a sample way to do
it. Additionally, there is an API to check for subscription state, so
you should check periodically to make sure the subscription is valid.
more information check Nikolay Elenkov's answer
What is the best for billing Either In app purchase or Paypal?
It is depends on the product type,
--> In app billing: Best for google in app billing,
For the digital products including downloadable content such as media
files or
photos, virtual content such as game levels or potions, premium
services and features, and more.
http://developer.android.com/google/play/billing/index.html
--> Paypal: Best for Paypal billing,
For physical content or product do you want to share. You are not
permitted to sell physical goods or services using 'In-App Purchasing'
since the goods purchased via this method must relate directly to the
app using them.
Purchase physical product from iPhone app without Apple in app purchase
Hope it will help you.
from the documentation:
Because the Google Play client now caches In-app Billing information
locally on the device, you can use the Version 3 API to query for this
information more frequently, for example through a getPurchases call.
Unlike with previous versions of the API, many Version 3 API calls
will be serviced through cache lookups instead of through a network
connection to Google Play, which significantly speeds up the API's
response time.
Which basically means you can look up the purchase each time and the Play Store app will respond pretty much right away.
From my experience I can assure you of one thing.
** In fact it's bad to put a flag with a bool saying if it's premium or not **.
What I do is obfuscate the shared code
After I create some strange strings or numbers that only identify through the code inside the app if the user is a premium user.
Along with this, except for a numeric code within the database that identifies the type of purchase. So by checking both I can make sure the user is premium.
At this point if they want to cheat me with the root of the phone they should first understand how the code of my app works and then understand where to interact, because if only the shared preferences change, nothing will change and they will be whipped.
** This doesn't translate to high security, but at least the security level is higher and the root won't be able to get a reward that easily. Also because they should understand what are the exact codes to insert in the shared, in the database and look for them by removing the obfuscation. I honestly don't think it's worth it for them. **
As what Kuffs has mentioned, it is best to query the app-side implementation of the In-App Billing library which in turn queries the device's Google Play client. This will ensure that the purchase history most recently obtained from the Google Play servers would be reliable and relatively fresh information.
Also, keep in mind that if you are distributing the app on Google Play you MUST use the Google Play payment mechanism via In-App Billing. As it stands, Google Play and Wallet do NOT yet support Paypal or wire/bank transfer methods so you should not integrate the option if you are releasing it on Play.
http://play.google.com/about/developer-content-policy.html#payments