Search code examples
google-playgoogle-play-developer-api

Programmatically Uploading Android App to Google Play Store


I am trying to build a helper class to upload my Android app to the Google Play Store testing track as part of my CI/CD pipeline. I did a bunch of Googling and found various examples, but none of them worked for me, and all of them were (apparently) using older versions of the AndroidPublisher API and calling deprecated methods.

So far, this is what I cobbled together. I am obtaining the GoogleCredentials object successfully, but what I can't figure out is where should I insert the accessToken or credentials into the request code?

public void uploadToGooglePlay(String applicationName, String packageName, String credentialFilePath, String aabFilePath) throws Throwable {
    NetHttpTransport httpTransport = new NetHttpTransport();

    JsonFactory jsonFactory = new GsonFactory();

    GoogleCredentials credentials = GoogleCredentials.fromStream(
            new FileInputStream(credentialFilePath)
    );

    credentials.createScoped(
            AndroidPublisherScopes.ANDROIDPUBLISHER
    );

    AccessToken accessToken = credentials.getAccessToken();

    HttpRequestInitializer httpRequestInitializer = httpTransport.createRequestFactory().getInitializer();

    AndroidPublisher.Builder androidPublisherBuilder = new AndroidPublisher.Builder(
            httpTransport,
            jsonFactory,
            httpRequestInitializer
    );

    androidPublisherBuilder.setApplicationName(applicationName);

    AndroidPublisher androidPublisher = androidPublisherBuilder.build();

    AndroidPublisher.Edits.Insert insert = androidPublisher.edits().insert(
            packageName,
            null
    );

    AppEdit appEdit = insert.execute(); // THIS IS LINE 73 IN THE ERROR BELOW

    String editId = appEdit.getId();

    FileContent fileContent = new FileContent(
            "application/octet-stream",
            new File(aabFilePath)
    );

    AndroidPublisher.Edits.Bundles.Upload upload = androidPublisher.edits().bundles().upload(
            packageName,
            editId,
            fileContent
    );

    Bundle bundle = upload.execute();

    System.out.println("Version Code: " + bundle.getVersionCode());
    System.out.println("SHA Hash: " + bundle.getSha256());
}

When I run this code, I get the following error:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.whatever.app/edits
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:118)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:37)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:428)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1111)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:514)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:455)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:565)
    at UploadToGooglePlay.uploadToGooglePlay(UploadToGooglePlay.java:73)
    at UploadToGooglePlay.main(UploadToGooglePlay.java:27)

I'm sure I'm missing something simple and obvious, but I have been pulling my hair out on this one for a while now.

Thanks in advance for any help!


Solution

  • I figured it out. The working code snippet is:

    InputStream googlePlayServiceCredentials = new FileInputStream(
        credentialFilePath
    );
    
    GoogleCredentials googleCredentials = GoogleCredentials
        .fromStream(googlePlayServiceCredentials)
        .createScoped(AndroidPublisherScopes.ANDROIDPUBLISHER);
    
    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(googleCredentials);
    
    AndroidPublisher.Builder androidPublisherBuilder = new AndroidPublisher.Builder(
        httpTransport,
        jsonFactory,
        httpRequestInitializer
    );
    

    However...

    The new Google OAuth 2 library does not support setting arbitraty connect/read timeouts on the HttpRequestInitializer, so this fails when uploading the AAB file (which takes forever). So I use the code above now for operations that don't involve uploading an AAB, and I use the code below (which includes deprecated methods, but there's no way around this from what I can see):

    InputStream googlePlayServiceCredentials = new FileInputStream(
        credentialFilePath
    );
    
    GoogleCredential credential = GoogleCredential.fromStream(
        googlePlayServiceCredentials
    ).createScoped(
        Set.of(
            AndroidPublisherScopes.ANDROIDPUBLISHER
        )
    );
    
    HttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() {
        @Override
        public void initialize(HttpRequest httpRequest) throws IOException {
            credential.initialize(httpRequest);
            httpRequest.setConnectTimeout(5 * 60 * 1000);
            httpRequest.setReadTimeout(5 * 60 * 1000);
        }
    };
    
    AndroidPublisher.Builder androidPublisherBuilder = new AndroidPublisher.Builder(
        httpTransport,
        jsonFactory,
        httpRequestInitializer
    );