PROGRAMMING

Google Play and Python - Checking the purchase and consumption status of an inapp item

#python , #google app engine

Some time ago I needed to check if a given package or subscription was purchased in a Google Play store. It seemed to be a simple task but i spent a lot of time on this. For the first time the way which is described in documentation does not work. Why? I don’t know. Every time when i asked API for subscription, API returned error message like “This developer account is not the owner of this application.” I was not a person who set up this application in store and i couldn’t check if this was correct but i hoped it was. The strange thing was that we could check request to the Android API on this account and this account can manage this application. After some time of testing i tried to use Google APIs Client Library for Python. That was another waste of time.

I knew that it would not work but why not try it if there were no other ideas. The same error message was returned. I got back to the way from documentation. I wrote the same code again because i thought that maybe i had made some mistake. After that.. still the same error. I could go on talking about this but it does not make sense. Someone created a new google account with the same application and.. the first code based on documentation worked correctly!

In this article i will describe how to use Google Android Publisher API https://developers.google.com/android-publisher/ with Python, how to check payments, refresh tokens, etc. I hope that this will help someone.

Some part of this will be write from my memory so if someone will find some mistake, let me know about this.

First, you will need OAuth access to your account. If you don’t have it, go to https://code.google.com/apis/console/ and create cliend ID. As application type choose “Web application”.

You will need also enabled Android API. Go to https://code.google.com/apis/console/, choose Services and turn on Google Play Android Developer API.

You will need access_token to be able to send authorized request to API everytime when you will want get pieces of information.

I had Google APIs Client Library for Python (from https://code.google.com/p/google-api-python-client/) so i used this for generarting access_token.

For example I will define variables where I will store Oauth information.

client_id = "EXAMPLE-123.apps.googleusercontent.com"
client_secret = "SECRET-EXAMPLE"
redirect_uri = "https://localhost/oauth2callback"

Now we need to generate code which is required for generating access_token. This operation will be executed only once.

from google_api.oauth2client.client import OAuth2WebServerFlow

flow = OAuth2WebServerFlow(
    client_id=client_id,
    client_secret=client_secret,
    scope="https://www.googleapis.com/auth/androidpublisher",
    redirect_uri=redirect_uri
)

auth_url = flow.step1_get_authorize_url()

print auth_url

"""
Read URL from auth_url and paste it to the browser. (You must be logged in
to your account) You will be asked about allowing to use this apllication
or  somethig like that. Allow it. After that it will redirect you to URL
from redirect_uri but with additional data. Copy code from this URL.
"""

code = "CODE_EXTRACTED_FROM_auth_url"

flow_credentials = flow.step2_exchange(code)

print flow_credentials.refresh_token

Good. Now we have a refresh_token. So at the moment we will need only the following data:

client_id = "EXAMPLE-123.apps.googleusercontent.com"
client_secret = "SECRET-EXAMPLE"
refresh_token = "refresh_token from flow_credentials.refresh_token"

We will also need to check and generate new tokens. We will use additional APIs - Google Token API and Google Token Info API. For later use i define ANDROID_PACKAGE_NAME.

ANDROID_PUBLISHER_API = 'https://www.googleapis.com/androidpublisher/v1.1/applications'
GOOGLE_TOKEN_API = 'https://accounts.google.com/o/oauth2/token'
GOOGLE_TOKEN_INFO_API = 'https://www.googleapis.com/oauth2/v1/tokeninfo'

client_id = "EXAMPLE-123.apps.googleusercontent.com"
client_secret = "SECRET-EXAMPLE"
refresh_token = "refresh_token from flow_credentials.refresh_token"
ANDROID_PACKAGE_NAME = "SOME_PACKAGE_NAME"

Before we will ask Android API we need to check if our access token is not expired. Token lives for 60 minutes and after that we need to generate a new one. So this is a example method for checking it. It returns True if token is not expired and it if will be live more than 100 seconds.

import requests

def get_check_token_from_google(token):
    token_info = requests.get('{}?access_token={}'.format(
        GOOGLE_TOKEN_INFO_API,
        token
    ))
    return token_info.ok and token_info.json()['expires_in'] > 100

If it will return True then we can use old token. If not, we need to generate a new one. This is a example method for generating a new token.

import requests

def get_refresh_token_from_google():
    data = dict(
        grant_type="refresh_token",
        client_id=client_id,
        client_secret=client_secret,
        refresh_token=refresh_token
    )

    token = requests.post(GOOGLE_TOKEN_API, data).json()

    return token['access_token']

It should return information like this:

{
    u'access_token': u'ACCESS_TOKEN',
    u'token_type': u'Bearer',
    u'expires_in': 3600
}

We can store this token for example in memcache. We can write additional method for this.

def get_token():
    token = memcache.get("GOOGLE_API_TOKEN")
    valid_token = True

    if token:
        valid_token = get_check_token_from_google(token)

    if not token or not valid_token:
        token = get_refresh_token_from_google()
        memcache.set("GOOGLE_API_TOKEN", token)

    return token

Now it is time for main method in this article - getting information about payments. Example method.

```python line-numbers import logging import requests from google_api.apiclient.errors import HttpError

def confirm_google_play_payment(product_name, product_id, purchase_token): try: response = requests.get( ‘{}/{}/inapp/{}/purchases/{}?access_token={}‘.format( ANDROID_PUBLISHER_API, product_name, product_id, purchase_token, get_token() ) ) except HttpError, err: logging.error(“{}: {}“.format( err.resp.status, json.loads(err.content)[‘error’][‘message’] )) return False

if not response.ok:
    logging.error('Android publisher error: {}'.format(response.reason))
    return False
else:
    return response.json()

Now we are able to check if someone bought given product in Google Play store.

Short explanation for confirm_google_play_payment method. It has three parameters.

- product_name - It is clear. Product name from Google Play store
- product_id - It is returned when someone will buy product on store
- purchase_token - It is returned when someone will buy product on store

All of above parameters are sent to this method by android application after product purchase.

Android Publisher API returns data like (if it is correct payment):

```javascript
{
    "consumptionState": 0,
    "purchaseState": 0,
    "kind": "androidpublisher#inappPurchase",
    "purchaseTime": "1374144297000"
}

Purchase time parameter is in milliseconds since the epoch (Jan 1, 1970) so it is possible that you will need to convert it. For example:

import datetime

transaction_date = datetime.date.fromtimestamp(
    long(purchaseTime) / 1000
)

One more thing. I don’t know why but default Android Publisher documentation is in version 1. I don’t remember how i found this but if you want version 1.1 go to https://developers.google.com/android-publisher/v1_1/. The only difference between versions is that the version 1 has only one resource type - purchases. Version 1.1 has additional resource type - inapppurchases.

And that is all. I think that i have described the most important things. If you have some questions, please ask. I hope that i will be able to answer you ;-)