Android purchase date of application - android

Is it possible to check what date the app was actually purchased, Not the in-app purchases, the actual date the user purchased the original application from the google store. I have found things like packageInfo.firstInstallTime, but that changes if you clear the device and reinstall etc.

I'm not sure if this is on-topic, but the only way to store data across installations is to persist it somewhere (like a server). You would have to get the gmail account associated with the purchase, associate a purchase ID and then check purchase date.
This is flawed because a re-install on a new device would look the same as a re-install on an existing device. It's also possible for a user to have two devices with the same gmail account, and therefore two (or more) active, valid installs and a single purchase. Most, but not all devices have a unique device ID.
And while there is no Official Google Play API (to request the data from Google), here is a good link for unofficial/creative options for search and content, but nothing for transaction data (which would probably lead to security risks without an official API):
how to get information of google play store in my android application?

Related

Android consumable in app purchase: get user information

Is there a way to check which users bought when a consumable of my app? Not in the app itself but in the developer console/order management. Currently I only see an order id and a token, but would need some custom information or at least the user's email address or sth like that...
Nope. You'll need to link purchases to userIds yourself. Google will link that purchase to the users Play Store account, so they can potentially restore the purchase if they've reinstalled the app or gotten a new phone.
If you don't want to manage your own server, it may be worth using a tool like RevenueCat, that offer a purchase/subscription backend-as-a-service.

Android LVL and InAppBilling: how to select current user account for purchase?

I use Google LVL and Google Inapp Billing API ver 3 in my java application for Android. Of course I use (slightly modified) LVL library project from Google extras and IAP jar that Google suggests.
LVL library LicenseValidator in verifyLicense receives ResponseData with user-id in it.
It is said in Google docs that it is an unique user ID, representing user's google account used for purchase.
So I assumed (and made sure in tests) it is the same string (for example, "ANlOH<...>ppA==") on all devices where user has logged in with the same Google account.
So here is my iap purchase protection scheme in short.
Before the purchase app sends user-id to my server. It generates an encrypted payload from user-id and sends it back. App makes a purchase request and puts payload in it. App receives a receipt signed by Google, that holds the same payload. App sends this receipt to my server with the current user-id. Server makes signature and other checks, compares user-ids from payload and from sender and if everything is fine sends files of iap item to the app.
In another scenario, when the user reinstalls the app to this or another device, app gets receipts belonging to him from InAppBilling, sends them to my server with the current user-id. Server performs the same checks and - if everything is fine - sends all needed files to the app.
This approach with small differences works well on other platforms. But I have experiencing some strange glitches recently on Android app.
My server logs receipt check issues and I have found strange errors: user with one user-id sent correctly signed receipts belonging to another user-id (payload in receipt holds that another user-id). When I started to investigate I've found that one of such strange "hacker attack" messages belongs to
one of my test devices while other belong to real users (according to order-ids in receipts).
This test device with Android 4.4.2 has several google accounts added in Settings.
Previously I was sure that Google uses the first account. I saw such log messages:
InAppBillingUtils.getPreferredAccount: com.mypackage.appname: Account from first account - [jbC...FgH]
But now I see that sometimes LVL uses not the first account, but another one. I see such messages in LogCat:
InAppBillingUtils.pickAccount: smpxg.mythdefdf: Account determined from library ownership - [boL...M5E]
Moreover, after fresh installation of my app InAppBilling returned receipts for one account, but LVL gave user-id of another! But this behaviour is not stable. For example, now I see that LVL and InAppBilling both think that second account is my primary and work with it as expected.
I assumed that both libraries will work side by side but it looks like I was wrong. Obviously when the app sends receipt belonging to user-id "...yUQ" along with current use-id "...ppA" to server it refuses to send purchased content. And he is right.
If user could change current account used for purchases, I'd just added this trick in FAQ. BUT I can't see a way to select it manually in settings. In addition, system somehow selects it in a random way! The only way to make things work is to ask a user to delete all accounts from the device except his primary, but it's a bad solution.
When user purchases iap item being logged into one account and then switches to another account he should expect not to see purchased item. It's a predictable behaviour, just like with purchasing apps. But he doesn't even know what account is used in the moment!
AFAIK, there's not way to get from InAppBilling service google user-id it selected for purchases.
But even if I could - having user-id changed randomly by system makes iap items to appear and disappear from time to time :)
Looks like Google advises to use developer payload for protection, but doesn't give any stable ID which can be used to identify particular account.
So my questions are:
Does anybody experience this strange account switching?
How can I be sure which account is current?
Is there any way to synchronize LVL and InAppBilling account
selection? Any workarounds?
Thank you in advance!
I havent had an exact experience with your issue, but this might be somewhat relevant
According to the In app billing documentation
If the device has more than one account, the purchase will be made with the account that downloaded the app. If none of the accounts has downloaded the app, the purchase is made with the first account.Users can confirm the account that is making a purchase by expanding the purchase dialog.

Android In-App-Purchase, how to check if user have purchased one item

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

Per Device subscriptions for purchases through Google Play

I would like to setup subscription based billing for an app that will be sold through Google Play. Is it possible to sell the same subscription to the same user but on a different devices? So that every device that user tries to use the app on would need an active subscription?
I was thinking I could store the device id and user id on my own server and authenticate it that way, but is it correct that a user can't purchase the same subscription more than once? So would I need a pool of basically the same subscriptions if the user wishes to purchase multiple "licenses"? Can Google Play Billing handle any of this natively?
Thanks
The documentation from Google initially seems to make this impossible to achieve but digging deeper, I uncovered the following...
In the Google Play API version 2.0, you could create what was called an "unmanaged" product type that allowed the user to purchase the same thing multiple times. That seems to have partly disappeared in API 3.0 although the Gooogle Developer Console clearly supports this. I assume it's still supported because apps that used the 2.0 API are still out there and Google just can't drop support for that.
In 3.0 however, the "unmanaged" product type is not listed in the API docs but the docs state the following about making multiple purchases for the same product type (one-time purchase or subscription):
If you are using the Version 3 API, you can also consume managed items
within your application. You would typically implement consumption for
items that can be purchased multiple times (such as in-game currency,
fuel, or magic spells). Once purchased, a managed item cannot be
purchased again until you consume the item, by sending a consumption
request to Google Play. To learn more about in-app product consumption,
see Consuming Items
http://developer.android.com/google/play/billing/api.html#consume
IMPORTANT: Subscriptions CANNOT be consumed which means that if you want the customer to periodically renew their license, you will have to contact them and tell them that they must purchase the license again. That's a downside if your service requires a periodic renewal.
To obtain what you are after, you will need a backend server to handle the registration of devices and store tokens the apps receive from Google Play when purchasing. When a user wants to purchase your license, feature, service (or whatever) from another device, the other device MUST first release its "ownership" of the product with Google Play, through a process known as "consuming". It would work something more or less like this:
The first device makes a purchase and receives a purchaseToken
string from Google Play.
The purchaseToken along with the device ID is sent from the app to your server and stored.
The user goes to the second device and wants to purchase the license as well for that device. The app first needs to go to your server and obtain the purchaseToken (that the first device uploaded) and then call Google Play with consumePurchase which releases the "ownership" of the product from the user.
The app then purchases the new license (or whatever) from Google Play, gets a new purchaseToken and stores it on your server along with its device ID.
In essence, Google Play won't keep track of which device has the product. It only associates the Google Account with the product being purchased. It's up to your app and server to manage the licenses.
There is one potential problem I see that you need to address. If for some reason the app fails to send the purchaseToken back to your server (your server is down, the user dropped their device and broke it, your app crashes before it saves the token on the device, etc.), then you may not know if the user paid for the service. Google does provide a server API that lets your backend server query Google Play on Google's server for information about purchases, but I'm not familiar with it nor its limitations.
You will need to implement in app purchases as you would for any other in app item.
Make sure when you create your item in the Dev Console, it is unmanaged, as managed items can only be purchased once per account.
When you receive a confirmation on purchase of your unmanaged item, send the details like the unique ID to your server and store them there.
Now whenever your app starts, check with your server if it is an authorized device. If it isn't, prompt the user to buy it. If it is, let them continue to the app.
This only works if you need a one time payment. If you need a subscription, you will have to make it up of multiple one time payments, as subscriptions are like managed purchases and can only be paid for once by any account.

In-App Billing Security and Design questions

I have a few questions connected to Android In-App Billing:
Is it possible to make a purchase from non-Market app? I understand that it would be a vulnerability, but I have no opportunity to find out if it's possible or not.
How can I get purchase state for a particular product? As far as I understand it can be done using RESTORE_TRANSACTIONS request, but it's not recommended to use very often. That's not a theoretical problem. My application allows users to buy content using in-app billing. Content can be downloaded from a server, and server must allow content downloading only if it was purchased. But it can't check if content was purchased or not without using signed response from Android Market.
How can I get price and description of an item from Android Market? Seems that I know the answer and it's "there's no way it can be done", but maybe I'm wrong. It would be very useful to have a possibility of retrieving item's price.
It's very interesting to me how you solved/are going to solve these problems in your apps. Answer to any of these questions will be appreciated.
In order:
1- Nope. The in-app billing process is part of Market. If the app comes from elsewhere, there's no way for Market to verify the origin/authenticity of the application.
2- It's your responsibility to store the purchase state for a particular product. From the doc:
You must set up a database or some other mechanism for storing users' purchase information.
RESTORE_TRANSACTIONS should be reserved for reinstalls or first-time installs on a device.
3- Unfortunately, at this time you're right. File a feature request!
In the meantime, one option is to set up a website with appengine, store listings of all your content & pricing there, and then manually sync prices listed on your appengine server with the updated prices in Market. Then have your Android app pull the data from the AppEngine server. This is much better than hardcoding price values into the app itself, since you don't need to have everyone update the app immediately to see accurate pricing whenever you change something. The only caveat of this method is that if the user is in a different country, in-app billing will display an approximated price in their native currency, and there's no way for you to determine exactly what price will be displayed to them.
Related, One of the Android Developer Advocates is giving a talk on LVL/IAP at IO, called "Evading Pirates and Stopping Vampires using License Verification Library, In-App Billing, and App Engine." - It would definitely be worth your while to watch when they release the session videos on the website.

Categories

Resources