Doing android purchase validation. API-V3 in Java.

Sukhmeet Singh
2 min readApr 16, 2018

--

Recently, I was building a mircoservice which demanded me to verify in-app billing for android purchase. The flow to buy a product is mostly in client and is documented here. The client side flow is simple and there are sample apps available too.

There is very less information available for server side validation to check if the purchase is actually valid. Not verifying your purchase can cause client side code emulation to unlock premium products. There are multiple apps available over play store which don’t require rooted device.

There are tons of fragmented links in order to do validation on stackoverflow. Since the API has changed over lots of iterations, there doesn’t seem to be a correct answer from all the accepted answers.

Here I will describe the steps I did to do purchase data validation over server side for google play store in-app API v3 over JAVA SDK.

Firstly, add the necessary dependencies. Note that you should always add the latest dependencies. These might be a outdated.

<dependency>            
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v2-rev60-1.23.0</version>
</dependency>

Create a google service account id using admin account for on Google Play console. This is currently available under API acess under Developer Account inside Settings. This service account id is needed at the time of making the API call to purchases. Store the valid .p12 or JSON file at a secured place.

Lets start with getting the purchase.

A valid purchase JSON looks like this.

 [Purchase. Json:         
{
"orderId":"GPA.3317-8176-4258-98671",
"packageName": package.name.test,
"productId":"gas",
"purchaseTime":1522934705928,
"purchaseState":0,
"purchaseToken":"ihincppnajieemhjhmkfekm.AO-J1OziSaRStKMr6GaGXyZWddwBnzWFqIGZtDQcV5t8Hw25989tQ9MeTTK6uURqkA2GJJNJiDBMUGpuTW2ZUoRqu-W3dz_E0KwS9gtosbuGGrXpori3GSs"
}
]

In order to verify the purchase

HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();    

JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
String applicationName = "testing app name";
String packageName = "package.name.test";
private final Set<String> scopes = Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER);GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(<service-account-id>)
.setServiceAccountScopes(scopes)
.setServiceAccountPrivateKeyFromP12File(
new File(KEY_FOLDER_PATH.getPath())) .build();

Pass the relevant params which were used by client for the purchase.

AndroidPublisher pub = new AndroidPublisher.Builder
(httpTransport, jsonFactory, credential)
.setApplicationName(applicationName)
.build();
final AndroidPublisher.Purchases.Products.Get get =
pub.purchases()
.products()
.get(packageName, productId, userPurchaseToken);
final ProductPurchase purchase = get.execute(); print("Found google purchase item ",purchase.toPrettyString());

That’s it. This will give the relevant purchase and throw error if the purchase is not found. Verify the purchase with the corresponding purchase on the client side. Also save it in a database for future validations and checks.

You can also modify it to get subscriptions but the core remains the same.

--

--