Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking google android subscriptions from server side

in a nutshell: Can I work with the Google Play Android Developer API from server-side without providing any app in the play store?

Background: I'm working on a project which provides apps with monthly subscriptions. The coresponding data of each subscription (purchase token, date etc) gets stored in the backend database. Now I want to create a cronjob that iterates through each of these datasets.And for each subscription I'd like to contact the Google API to retrieve the information if the subscription is still valid or not, and update our database corresponding to the responsed status.

For the backend logic I use the google-api-java-client library.

To either cancel or verify subscriptions I need to authenticate myself with OAuth2 before. Been there, done that.

new GoogleCredential.Builder()
    .setTransport(HTTP_TRANSPORT)
    .setJsonFactory(JSON_FACTORY)
    .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
    .setServiceAccountScopes("https://www.googleapis.com/auth/androidpublisher") // $1
    .setServiceAccountPrivateKeyFromP12File(new File(filePath))
    .setClientSecrets(CLIENT_ID, CLIENT_SECRET) // $2
    .build();

$1: I don't know if the given account scope is valid. Because I just could find this value in a very few examples, but neither in this overview nor in the google playground

$2 I guess this is necessary, even though I found a lot of example which did not provide this information.

But, unfortunately, I can't see any differences when I provide invalid data (like wrong email or private key).

Questions

  • How can i verify that the GoogleCredential is correct?
  • May I just see it in the next steps, like contacting ie the androidpublisher API?

In the next step I try to get purchase status of a subscription:

Androidpublisher publisher = new Androidpublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                               .setApplicationName(GOOGLE_PRODUCT_NAME) // $1                
                               .build();
Androidpublisher.Purchases purchases = publisher.purchases();
Androidpublisher.Purchases.Get get = purchases.get("android.test.purchased", "monthly001", "mytoken"); // $2
SubscriptionPurchase subscripcion = get.execute(); 

$1: My dummy product name from the API console -> API Access

$2: Beside the fact, that the androidpush API does not allow contacting it via service accounts, but only via web server applications auth flow, I don't have any clue what to insert in the parameter of the get- method.

Here's the API: https://developers.google.com/android-publisher/v1/purchases/get

Questions

  • What is the package name and what is the subscriptionId in this context?
  • Where do I get/set these values?

After reading this document I know there is a way to to deal with fake/static responses. But I can't read anywhere if this is also possible for subscriptions, or just for in-app-billings on mobile devices only.

I'm wondering anyway why/if there is any easy way of developing with a sandbox or s.th. simliar.

I still have the feeling that I'm just missing a big part to understand how the things should work. Maybe someone of you can give me a hint how to proceed at this place or may say me where i'm wrong.

Kind regards,

Christopher

like image 557
Christopher Will Avatar asked Oct 06 '22 12:10

Christopher Will


1 Answers

I could now figure out most of my previous understanding problems.

=1= GENERATE AUTHORIZATION URL

String authorizeUrl = new GoogleAuthorizationCodeRequestUrl(googleClientId,callbackUrl,"https://www.googleapis.com/auth/androidpublisher").build()    
// See why: http://stackoverflow.com/questions/8433990/when-authenticating-with-oauth-and-youtube-always-get-error-invalid-grant-on
authorizeUrl += "&approval_prompt=force&access_type=offline"

=2= AUTHENTICATE

Since the server-webflow is not working for the androidpublisher API the customer must now call the URL generated in (1) manually.

=3= CALLBACK

The google callback should process the next steps. The callback contains the parameter "code" which we have to use.

=4= REQUEST AUTH-TOKEN

    // Build the HTTP parameter
    Map<String,String> params = [:]
    params.put("grant_type", "authorization_code")
    params.put("code", code.encodeAsURL())
    params.put("client_id", customer.googleClientId.encodeAsURL())
    params.put("client_secret", customer.googleClientSecret.encodeAsURL())
    params.put("redirect_uri", getCallbackUrl().encodeAsURL())

    // Send the POST request
    // This action might throw an exception in case any parameter were wrong, invalid or not specified.
    String result = HttpRequestHandler.sendRequest("https://accounts.google.com/o/oauth2/token", params);
    JSONElement jsonResult = JSON.parse(result)

    // Map result
    OAuth2Result oAuth2Result = new OAuth2Result()
    oAuth2Result.accessToken = jsonResult.getAt("access_token")
    oAuth2Result.refreshToken = jsonResult.getAt("refresh_token")
    oAuth2Result.ttlSeconds = Integer.parseInt(jsonResult.getAt("expires_in").toString())
    oAuth2Result.tokenType = jsonResult.getAt("token_type") 

=5= REQUEST REFRESH TOKEN

    // Build the HTTP parameter
    Map<String,String> params = [:]
    params.put("grant_type", "refresh_token")
    params.put("refresh_token", this.customer.googleRefreshToken.encodeAsURL())
    params.put("client_id", customer.googleClientId.encodeAsURL())
    params.put("client_secret", customer.googleClientSecret.encodeAsURL())

    // Send the POST request
    // This action might throw an exception in case any parameter were wrong, invalid or not specified.
    String result = HttpRequestHandler.sendRequest("https://accounts.google.com/o/oauth2/token", params);
    JSONElement jsonResult = JSON.parse(result)

    // Map result
    OAuth2Result oAuth2Result = new OAuth2Result()
    oAuth2Result.accessToken = jsonResult.getAt("access_token")
    oAuth2Result.refreshToken = jsonResult.getAt("refresh_token")
    oAuth2Result.ttlSeconds = Integer.parseInt(jsonResult.getAt("expires_in").toString())
    oAuth2Result.tokenType = jsonResult.getAt("token_type")
like image 161
Christopher Will Avatar answered Oct 10 '22 02:10

Christopher Will