6

I am upgrading AndroidPublisher library from v1 to v3 for my secure backend server. AndroidPublisher library (v3) will allows me to do server side purchase validation and acknowledgement for in-app purchases and subscription securely.

Existing code for v1 is not compatible anymore. The v3 library looks better but I could not find any sample code for:

  1. Build client credential using client JSON.
  2. Get & Acknowledge Purchases using PurchaseToken.

Maven setting:

<project>
  <dependencies>
    <dependency>
      <groupId>com.google.apis</groupId>
      <artifactId>google-api-services-androidpublisher</artifactId>
      <version>v3-rev103-1.25.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.api-client</groupId>
        <artifactId>google-api-client</artifactId>
        <version>1.30.2</version>
    </dependency>
  </dependencies>
</project>

API documentation: https://developers.google.com/android-publisher/api-ref/purchases/products/get

Looking for a sample like this: https://developers.google.com/api-client-library/java/google-api-java-client/samples

Any short sample code would be a great help.

Roy
  • 673
  • 11
  • 21

3 Answers3

22

Add following dependencies

compile "com.google.apis:google-api-services-androidpublisher:v3-rev103-1.25.0"
compile "com.google.auth:google-auth-library-oauth2-http:0.17.1"

Then enable Google Developer Play Api library from Google Cloud Console here

In credentials Create service account key with role Pub/Sub Admin and save json file

In Google developers Console here. In Settings >> Developer Account >> API Access link your app.

Then in code do following to get subscription info.

GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("<service-account-key-file>.json")).createScoped(AndroidPublisherScopes.ANDROIDPUBLISHER);

AndroidPublisher pub = new AndroidPublisher.Builder(
        GoogleNetHttpTransport.newTrustedTransport(),
        JacksonFactory.getDefaultInstance(),
        new HttpCredentialsAdapter(credentials)
).setApplicationName("<app-name>").build();
SubscriptionPurchase purchase = pub.purchases().subscriptions().get(
        "<app-package>",
        "<subscription-id>",
        "<purchase-token>"
).execute();
println(purchase);

Note: if you get this error:

The current user has insufficient permissions to perform the requested operation.

Then try again after one day because after enable google play developer api and creating service account key from google console you need to wait 24 to 48 hours and also do following

From Google Play Console go to (with admin access):

  1. Setting (Left Panel) Developer Account (Left Panel) Users & permissions (Left Panel)
  2. Click on the Invite New User button.
  3. Enter the service account email (the same you have in the json file you are using and that google generated when you created the service account)
  4. Select Administrator in the Role DropDown menu.
  5. Click on SEND INVITATION
Sabeeh
  • 1,478
  • 15
  • 15
  • Is there any method to acknowledge the subscription? The documentation claims there is one but they provide nothing else. The only one I can find is: purchases.subscriptions().acknowledge() and that does not work. – foolioJones Nov 17 '19 at 17:23
  • 1
    If you get an error that your project is not connected and your sure it is, try disabling and re-enabling a product, creating a new product or something in this realm, it seems to refresh things on googles end. – MobDev Sep 05 '20 at 01:03
  • Thanks, this works. +1 to deactivating and activating an in-app product from console makes the error "The current user has insufficient permissions to perform the requested operation." go away – 0case May 16 '21 at 20:55
  • Thank you so much for this example, I can confirm it is working! If you get insufficient permissions error, just change one in app product (e.g. description), and it will work after 1-2 minutes (no need to wait 24 hours+) found that hint on another website – AndyB May 20 '21 at 15:30
  • FYI `GoogleCredentials` can be used from project-wide settings https://googleapis.dev/java/google-auth-library/latest/com/google/auth/oauth2/GoogleCredentials.html#getApplicationDefault-- - my preference is `GOOGLE_APPLICATION_CREDENTIALS` environment variable – Mixaz Oct 08 '21 at 15:49
  • I used `com.google.api.client.googleapis.util.Utils.getDefaultJsonFactory()` instead of `JacksonFactory.getDefaultInstance()`, because the latter wasn't found on classpath. – trebor May 07 '22 at 23:44
  • i am getting error 400, bad request error, after exeuting request. can you help me? – mrsamkhar Sep 06 '22 at 13:16
0

@Sabeeh answer works.

Here is an example on how to fetch (server-side) a purchase using token and product id in kotlin:

    suspend fun playstoreVerifier(productId: String, token: String) = withContext(Dispatchers.IO){
        androidPublisher.Purchases().products().get(PACKAGE_NAME, productId, token).execute()?.let {
            println("ack ${it.acknowledgementState}")
        }
    }
0case
  • 443
  • 7
  • 13
0

Google's documentation here is horrible, no clear examples of implementation. I finally found the answer after a LOT of Googling thanks to @Sabeeh's answer and lots of other snippets spread out online.

1. First step is to add the dependencies:

implementation "com.google.apis:google-api-services-androidpublisher:v3-rev142-1.25.0" // Update based on latest release
implementation "com.google.auth:google-auth-library-oauth2-http:1.12.1" // Update based on latest release

2. Follow these steps to link the Google Play Console with Google Play Developer API (choose the "Use a service account", not "Use OAuth clients" and follow until "Additional information").

3. Download the services JSON file from your Google Cloud service account (click on the account that you set up in the previous step). You can find/create this file under the "Manage Keys" action or the "Keys" tab. Add the exported JSON file in your assets folder in Android

4. Then you can call the Google Play Developer API to query subscriptions like this (important to call from a Thread, didn't work from the UI thread, not sure why):

new Thread(() -> {
    InputStream inputStream = context.getAssets().open("service_account_google_play.json"); // JSON file from step 3
    GoogleCredentials credentials = GoogleCredentials.fromStream(inputStream)
                    .createScoped(AndroidPublisherScopes.ANDROIDPUBLISHER);
    AndroidPublisher androidPublisher = new AndroidPublisher(
        new NetHttpTransport(),
        JacksonFactory.getDefaultInstance(),
        new HttpCredentialsAdapter(credentials)
    );
    SubscriptionPurchase purchase = androidPublisher.purchases().subscriptions().get(
        context.getPackageName(), subscriptionId, purchaseToken
    ).execute();
    // Do with the purchase object what you want here
}).start();

At the risk of being overly descriptive, the subscriptionId is the ID of your subscription in the Play Console (e.g. subscription_monthly or whatever you called it), and the purchaseToken is the token you get from the Purchase token after querying the BillingClient (querying subscriptions is explained in detail here).

Let me know if anything is unclear or doesn't work yet. This took me 6 hours to figure out and I'm happy to save others that pain.

Jorn Rigter
  • 745
  • 1
  • 6
  • 25