Skip to end of metadata
Go to start of metadata

Plugin Information

View Google Play Android Publisher on the plugin site for more information.

Older versions of this plugin may not be safe to use. Please review the following warnings before using an older version:

Enables Jenkins to upload Android apps (APK files) and related info to Google Play.

Features

  • Uploading APK files to Google Play
    • This includes apps which use Multiple APK support
    • ProGuard mapping.txt files can also be associated with each APK, for deobfuscating stacktraces
  • Uploading APK expansion (.obb) files
    • With the option to re-use expansion files from existing APKs, e.g. for patch releases
  • Assigning apps to alpha, beta or production release tracks
    • This includes a build step for moving existing APKs to a different track
    • e.g. You can upload an alpha in one job, then later have another job promote it to beta
  • Staged rollout of production apps
  • Assigning release notes to uploaded files, for various languages
  • Changing the build result to failed if the configuration is bad, or uploading APKs fails for some reason
  • Every configuration field supports variable and token expansion, allowing release notes to be dynamically generated, for example
  • Integration with the Google OAuth Plugin, so that credentials can be entered once globally and shared between jobs
    • Multiple Google Play accounts are also supported via this mechanism

Potential upcoming features

  • Uploading screenshots and text for the app
  • Updating recent changes text on an existing APK (JENKINS-32109)

Requirements

Jenkins

Jenkins version 2.32 or newer is required.

Google Play publisher account

For the initial setup only, you must have access to the Google account which owns the Google Play publisher account.

This is required to enable API access from Jenkins to your Google Play account.

Note that having admin access is not enough; you need the account owner.
You can see who the account owner is under Settings → User accounts & rights in the Google Play developer console.

Please note

  • Any APKs uploaded will be published by Google Play immediately; they will not be held in a draft or pending state
    • Google Play did add timed publishing in October 2015, which enables changes to be queued and released later. However, as with most new features, this isn't available via the Google Play API, and therefore this plugin cannot use it
    • Similarly, Google Play added the ability to prepare releases and artifacts during 2016, but also did not provide an API for this
      (actually, this might be possible with version 3 of the API…)
  • The app being uploaded must already exist in Google Play; you cannot use the API to upload brand new apps

Setup

One-time: Set up Google Play credentials

The following initial setup process is demonstrated in this video: https://www.youtube.com/watch?v=txdPSJF94RM
(note that Google has changed the Google API Console (twice) since this video was recorded; steps 3–13 in the "Create Google service account" section below have the updated info)

Install plugin

Install this plugin via the Jenkins plugin manager.
Or if installing the plugin via other means, ensure that the prerequisite Google OAuth Plugin, Token Macro Plugin and their dependencies are also installed.

Create Google service account

To enable automated access to your Google Play account, you must create a service account:

  1. Sign in to the Google Play developer console as the account owner
  2. Select Settings → Developer account → API access
  3. Under Service Accounts, click "Create Service Account"
  4. Follow the link to the Google API Console
  5. Click the "Create service account" button
  6. Give the service account any name you like, e.g. "Jenkins"
  7. Choose Service Accounts > Service Account User for the "Role" field
  8. Enable "Furnish a new private key"
  9. Choose "JSON" as the key type (P12 works as well, but JSON is a little simpler)
  10. Click the "Save" button
  11. Note that a .json file is downloaded, named something like "api-xxxxxxxxx-xxxxx-xxxx.json"
  12. Close the dialog that appears
  13. Copy the email address of the new user (something like "jenkins@api-xxxxxxxxx-xxxxx-xxxx.iam.gserviceaccount.com")
  14. You can now close the page

Assign permissions to the service account

  1. Return to the Google Play developer console page
  2. Click "Done" on the dialog
  3. Note that the service account has associated with the Google Play publisher account
    1. If it hasn't, follow these additional steps before continuing:
    2. Click "Users & permissions" in the menu
    3. Click "Invite new user"
    4. Paste in the email address you copied above
    5. Continue from step 5
  4. Click the "Grant access" button for the account (e.g. "jenkins@api-xxxxxxxxx-xxxxx-xxxx.iam.gserviceaccount.com")
  5. Ensure that at least the following permissions are enabled:
    • View app information — this is always required
    • Manage production releases — if you want to upload APKs to production, or a staged rollout
    • Manage testing track releases — if you want to upload APKs to alpha, beta, or internal
  6. Click "Add user" (or "Send invitation", as appropriate)
  7. You can now log out of the Google Play publisher account

Add the service account credentials to Jenkins:

  1. Navigate to your Jenkins instance
  2. Select "Credentials" from the Jenkins sidebar
  3. Choose a credentials domain and click "Add Credentials"
  4. From the "Kind" drop-down, choose "Google Service Account from private key"
  5. Enter a name for the credential — the actual value is not important
  6. Choose the "JSON key" type
  7. Upload the .json file that was downloaded by the Google API Console
  8. Click "OK" to create the credential

Jenkins now has the required credentials and permissions in order to publish to Google Play.

Once you've set up a job (see the next section) and confirmed that uploading works, either delete the downloaded JSON file or ensure that it's stored somewhere secure.

Per-job configuration

Freestyle job configuration

Uploading an APK

The following job setup process is demonstrated in this video: https://www.youtube.com/watch?v=iu-bLY9-jkc

  1. Create a new free-style software project
  2. Ensure, via whatever build steps you need, that the APK(s) you want to upload will be available in the build's workspace
  3. Add the "Upload Android APK to Google Play" post-build action
  4. Select the credential name from the drop-down list
    • The credential must belong to the Google Play account which owns the app to be uploaded
  5. Enter paths and/or wildcards pointing to the APK or APKs to be uploaded
    • This can be an Ant-style **/*-release.apk pattern, or a comma-separated list of filenames, relative to the root of the workspace
  6. Choose the track to which the APKs should be deployed
  7. Optionally choose "Add language" to associate release notes with the uploaded APK(s)
    • You add entries for as many or as few of your supported language as you wish, but each language must already have been added to your app, under the "Store Listing" section in the Google Play Developer Console.
APK expansion files

You can optionally add up to two expansion files for each APK being uploaded.

A list of expansion files can be specified in the same way as APKs, though note that they must be named in the format [main|patch].<expansion-version>.<package-name>.obb.

See the inline help for more details.

Moving existing APK(s) to another release track

If you have already uploaded an app to the alpha track (for example), you can later use Jenkins to re-assign that version to the beta or production release track.
Under the "Build" section of the job configuration, add the "Move Android APKs to a different release track" build step and configure the new release track.

You can tell Jenkins which APKs to be moved by either entering the APK version codes directly, or by providing the APK files, from which the plugin will read the application ID and version codes for you.

Pipeline job configuration

As of version 1.5, this plugin supports the Pipeline Plugin syntax. You can generate the required Pipeline syntax via the Snippet Generator, but some examples follow.

Note that you should avoid using these steps in a parallel block, as the Google Play API only allows one concurrent "edit session" to be open at a time.

Uploading an APK

The androidApkUpload step requires at least the Google Play credential ID, a list of APK(s) to upload, and the track to assign them to:

androidApkUpload googleCredentialsId: 'My Google Play account', apkFilesPattern: '**/*.apk', trackName: 'production'

Uploading the ProGuard mapping file(s) to be associated with the APK(s) just requires one more more patterns in addition:

androidApkUpload googleCredentialsId: 'My Google Play account', apkFilesPattern: '**/*.apk',
                 deobfuscationFilesPattern: '**/mapping.txt', trackName: 'production'

Performing a staged rollout requires the rollout percentage as a string; the percentage sign is optional:

androidApkUpload googleCredentialsId: 'GP', apkFilesPattern: '**/*.apk', trackName: 'production', rolloutPercentage: '50%'

Adding "recent changes" text requires specifying a list:

androidApkUpload googleCredentialsId: 'GP', apkFilesPattern: '**/*.apk', trackName: 'alpha',
                 recentChangeList: [
                     [language: 'en-GB', text: "Please test the changes from Jenkins build ${env.BUILD_NUMBER}."],
                     [language: 'de-DE', text: "Bitte die Änderungen vom Jenkins Build ${env.BUILD_NUMBER} testen."]
                 ]

To upload expansion files, reusing those from the previous upload where possible:

androidApkUpload googleCredentialsId: 'GP', apkFilesPattern: '**/*.apk', trackName: 'production',
                 expansionFilesPattern: '**/patch.obb',
                 usePreviousExpansionFilesIfMissing: true
Moving existing APK(s) to another release track

The androidApkMove step requires at least the Google Play credential ID and the track to move APK(s) to, plus either an application ID and version code(s), or APK file(s) to read this information from.

Moving APKs from alpha to beta, specifying the application ID and version codes:

androidApkMove googleCredentialsId: 'My Google Play account',
               applicationId: 'com.example.app',
               versionCodes: '1050, 2050, 3050',
               trackName: 'beta'

Moving APKs from beta to staged rollout, specifying the application ID and version codes via the uploaded APKs:

androidApkMove googleCredentialsId: 'My Google Play account',
               fromVersionCode: false,
               apkFilesPattern: '**/*.apk',
               trackName: 'production',
               rolloutPercentage: '5'

Feedback wanted

If you're a user of expansion files, especially if you use multiple APKs, it would be helpful to know how you normally use expansion files, and whether what the plugin provides is adequate.
Do you normally have separate main/patch expansion files for each of the APKs, or is it more common for all APKs to share the same expansion files?

Currently the former case isn't possible when trying to re-use expansion files from existing APKs (without having you explicitly specify which expansion files from which old APKs should be re-used with which newly-uploaded APKs).

Let me know via the maintainer email at the top of the page!

Troubleshooting

Error messages from the plugin (many of which come directly from the Google Play API) should generally be self-explanatory.
If you're having trouble getting a certain config to work, try uploading the same APKs manually to Google Play. There you'll likely see the reason for failure, e.g. a version code conflict or similar.

Otherwise, please file a bug report or send an email with details, including the build console log output; see info box at the top of the page.

Some known error messages and their solutions are shown below:

GoogleJsonResponseException: 401 Unauthorized

This means that the Google service account does not have permission to make the changes that you requested.

Make sure that you followed the setup instructions above, and confirm that the service account you are using in this Jenkins job has the appropriate permissions for the app that you are trying to change.

GoogleJsonResponseException: 500 Internal Server Error

Unfortunately, the Google Play API sometimes is not particularly reliable, and will throw generic server errors for no apparent reason.

In these cases you can try running your build again, or wait a few hours before retrying, if the problem persists.

Please also consider contacting Google Play Developer Support to help make them aware that people use the Google Play API, and that it should preferably work in a reliable manner.

This plugin already recognises some temporary Google Play API server problems and works around them; more workarounds may be added in future, e.g. automatically retrying when a generic server error is encountered.

Unable to retrieve an access token with the provided credentials

If you see this error message, look further down the error log to see what is causing it. Below are a couple of common causes:

Invalid JWT: Token must be a short-lived token and in a reasonable timeframe

Ensure that the time is correctly synchronised on the build machine, and then try again.

java.net.SocketTimeoutException: connect timed out

This likely means your build machine is behind an HTTP proxy.

In this case, you should set up Jenkins as documented on the JenkinsBehindProxy page.

This plugin only makes secure (HTTPS) requests, so you need to make sure that the -Dhttps.proxyHost=<hostname> and -Dhttps.proxyPort=<port> Java properties are set when starting Jenkins. Add the appropriate http versions of those flags too, if unsecured HTTP requests also need to go through the proxy.

Frequently asked questions

What if I want to upload APKs with multiple, different application IDs (i.e. build flavours)?

Using the build flavours feature of the Android Gradle build system, it's possible to have a single Android build which produces multiple APKs, each with a different application ID.
e.g. You could have application IDs "com.example.app" and "com.example.app.pro" for free and paid versions.

As these will often be built in a single Jenkins job, people have wondered why this plugin will refuse to upload APKs with differing application IDs in a single freestyle job.

However, as far as Google Play is concerned, these are completely separate apps. This is correct and, as such, they should be uploaded in separate Jenkins builds: one per application ID.

If the plugin did allow this and you were to attempt to upload, say three, completely different APKs in one Jenkins build, this would require opening and committing three separate "edit sessions" with the Google Play API. If any one of these were to fail — maybe because of an invalid APK, versionCode conflict, or due to an API failure (which, unfortunately, is not uncommon with the Google Play API) — you would end up with your Google Play account in an inconsistent state. Your Jenkins build would be marked as failed, but one or more applications will have actually been uploaded and published to Google Play, and you would have to fix the situation manually. Also, you would not be able to simply re-run the build, as it would fail due to already-existing APKs.

The best practice in this case would be to have one job that builds the different flavours (i.e. the APKs with different application IDs) and then, if the build is successful, it would archive the APKs and start multiple "downstream" Jenkins builds which individually publish each of the applications.
This can be achieved, for example, with the Parameterized Trigger Plugin and the Copy Artifacts Plugin, i.e. the "upload" job could be generic, and would receive the APK information via parameter.

Alternatively, if you have version 1.5 of this plugin, and use the Pipeline Plugin, you should be able to use the androidApkUpload step multiple times within a single build.

Version history

Version 1.8 (June 3, 2018)

  • Enabled ability to upload to the "internal" track (thanks to Serge Beauchamp)
  • Allowed arbitrary percentage values to be used for staged rollouts
  • Fixed potential NullPointerException if something went wrong (JENKINS-49789)

Version 1.7 (February 26, 2018)

Version 1.6 (January 18, 2018)

  • Added ability to upload ProGuard mapping files (JENKINS-38731)
  • Made it possible to specify the Google Play credential dynamically (JENKINS-38613)
  • Updated Google Play API dependency to hopefully make uploads a bit more stable
  • Improved various error messages and configuration validation
  • Increased minimum Jenkins version to 2.32
  • Thanks to Christopher Frieler and Dragan Marjanovic

Version 1.5 (September 8, 2016)

Version 1.4.1 (August 27, 2015)

  • Ensured that the required Token Macro Plugin is installed (see JENKINS-29887)

Version 1.4 (July 30, 2015)

  • Fixed the Google Play credential being forgotten when editing a job's configuration (see JENKINS-26542)
  • Improved error messages when Google Play credentials are missing or misconfigured (see JENKINS-25933)
  • Improved error messages shown when reading info from an APK fails
  • Fixed or improved various aspects of job configuration validation
  • Added additional logging about the credential ID and app ID being used
  • Integrated the Token Macro Plugin to give more options for specifying "Recent Changes" text (or any other field)
    • For example, with version 1.11 of token-macro, it will be possible to use something like ${FILE, path="changes-en.txt"}, to read a changelog from the workspace and use its contents as release notes when uploading an APK to Google Play

Version 1.3.1 (April 1, 2015)

  • Improved the logging of which and how many APK files are to be uploaded/re-assigned

Version 1.3 (March 22, 2015)

  • Added new build step to enable moving existing APKs to a different release track

Version 1.2 (November 1, 2014)

  • Added ability to automatically recover from API failures when committing changes, if possible (see JENKINS-25398)

Version 1.1 (October 27, 2014)

  • Added ability to upload APK expansion files
  • Upgraded APK parser library to fix some potential crashes

Version 1.0 (October 4, 2014)

  • Initial release

44 Comments

  1. Hi,

    How can I upload file content in the "Recent Changes" section,

    I tried 

    $

    Unknown macro: {FILE, path="releaseNotes.txt"}

    but no luck...

    1. I'm afraid you can't use that syntax — but it's not a bad idea, similar to how various token macro plugins work. I'll think about adding that (smile)

      As a workaround, you could use the EnvInject plugin to export the release notes file as an environment variable.
      Something like this:

      1. Install the EnvInject plugin
      2. In your job config, add a "Execute shell" build step with:

      echo -n RELEASE_NOTES= > temp.properties
      cat releaseNotes.txt | sed 's/$/\\/g' >> temp.properties
      

      3. Add a "Inject environment variables for your job" build step
      4. Set "Envionment properties file path" to your "temp.properties" file

      Now there should be an environment variable called $RELEASE_NOTES, which you can use with the APK upload plugin.

      I haven't tested this description, but it should pretty much work. If you're on Windows, I don't know what the equivalent commands are.

    2. I added this feature request to the issue tracker https://issues.jenkins-ci.org/browse/JENKINS-26453

      Since then, version 1.4 of the plugin has been released, which integrates the Token Macro plugin, which provides functionality like this.

      However, the ${FILE} functionality won't be available until a Token Macro version newer than 1.10 is released. Once it is released, you will be able to upgrade Token Macro, and this functionality will become available to you.

  2. Hello,

    I am trying to use a jenkins job to iterate over many apks and calling a second jenkins job that handles the upload.

    I pass the What's New information through an exported variable in a .properties file (from the first job) and then inject it in the uploader job.

    The problem is that a "multiline What's New" gets \n and other escaped characters  with \

    For example: 

    -Stability fixes

    -UI enhancements

    Thank you for your feedback!

    gets converted to:-Stability fixes\n-UI enhancements\n\nThank you for your feedback!

    and gets uploaded that way.

    What should I do?

    1. Could you possibly file a bug for that, with an example of how you're creating the file and what it looks like?

      We can try and figure out whether it's an EnvInject issue, or an issue with this plugin, or the API or whatever.

      Though I did test something similar recently this plugin and it worked. I believe that multi-line environment variables work as well.

  3. Hi there,

    Is there a way I can just upload the apk to the google play store and not publish it right away?

    I need to include this step in my production builds being done from Jenkins and I would like to upload every prod build to google play store and then manually go it and select whichever one I want to publish and delete the rest.

    Thanks

    Rishi

    1. There's no way to do this via the API (nor the web UI) as far as I'm aware.

  4. Hi,

    we manage several Google accounts and we have to set different credentials for every job. Plugin works perfectly this way, but when we enter the configure section in a job, credentials dropdown selector always preselect the first one ignoring the previous saved one. So, if users don't pay attention to it, they will probably change the right credential when saving configuration.

    Could you please check this out and fix it if is necessary?

    In case we are doing something wrong within the plugin, please tell us how to get this working.

    Thanks for your work and help,

    David

    1. Yeah, sorry, that's an issue I also noticed recently. I agree it's annoying; I'll try and fix it soon.

      I'll track changes to that in https://issues.jenkins-ci.org/browse/JENKINS-26542


      Update: Version 1.4 of the plugin has been released, which fixes this issue.

  5. L B

    Hi. I'm still getting error :( Can it work with proxy?
    Upload failed: org.jenkinsci.plugins.googleplayandroidpublisher.UploadException: java.security.GeneralSecurityException: Unable to retrieve an access token with the provided credentials
    21:30:53 at org.jenkinsci.plugins.googleplayandroidpublisher.CredentialsHandler.getServiceAccountCredentials(CredentialsHandler.java:60)
    21:30:53 at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.perform(ApkPublisher.java:301)
    21:30:53 at hudson.tasks.BuildStepMonitor$2.perform(BuildStepMonitor.java:32)
    21:30:53 at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
    21:30:53 at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:726)
    21:30:53 at hudson.model.Build$BuildExecution.post2(Build.java:185)
    21:30:53 at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:671)
    21:30:53 at hudson.model.Run.execute(Run.java:1766)
    21:30:53 at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
    21:30:53 at hudson.model.ResourceController.execute(ResourceController.java:98)
    21:30:53 at hudson.model.Executor.run(Executor.java:408)
    21:30:53 Caused by: java.security.GeneralSecurityException: Unable to retrieve an access token with the provided credentials
    21:30:53 at com.google.jenkins.plugins.credentials.oauth.RemotableGoogleCredentials.<init>(RemotableGoogleCredentials.java:70)
    21:30:53 at com.google.jenkins.plugins.credentials.oauth.GoogleRobotCredentials.forRemote(GoogleRobotCredentials.java:204)
    21:30:53 at org.jenkinsci.plugins.googleplayandroidpublisher.CredentialsHandler.getServiceAccountCredentials(CredentialsHandler.java:36)
    21:30:53 ... 10 more
    21:30:53 Caused by: java.net.SocketTimeoutException: connect timed out
    21:30:53 at java.net.PlainSocketImpl.socketConnect(Native Method)
    21:30:53 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    21:30:53 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    21:30:53 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    21:30:53 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    21:30:53 at java.net.Socket.connect(Socket.java:579)
    21:30:53 at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:618)
    21:30:53 at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    21:30:53 at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
    21:30:53 at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
    21:30:53 at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:275)
    21:30:53 at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:371)
    21:30:53 at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191)
    21:30:53 at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:932)
    21:30:53 at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177)
    21:30:53 at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
    21:30:53 at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
    21:30:53 at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:77)
    21:30:53 at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:965)
    21:30:53 at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:283)
    21:30:53 at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
    21:30:53 at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
    21:30:53 at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
    21:30:53 at com.google.jenkins.plugins.credentials.oauth.RemotableGoogleCredentials.<init>(RemotableGoogleCredentials.java:64)
    21:30:53 ... 12 more

    1. If your Jenkins instance needs to access the internet via a proxy, then you need to set it up as documented here: https://wiki.jenkins-ci.org/display/JENKINS/JenkinsBehindProxy#JenkinsBehindProxy-HowJenkinshandlesProxyServers

      This plugin only makes secure (HTTPS) requests, so you need to make sure that the -Dhttps.proxyHost=<proxy-hostname> and -Dhttps.proxyPort=<proxy-port> Java properties are set when starting Jenkins. Add the appropriate http versions of those flags too, if unsecured HTTP requests also need to go through the proxy.

      I just tested this and it worked for me, when I placed Jenkins behind a proxy.

  6. Hello,

    I started receiving the following exception in my build script when trying to upload to google play, can anyone help regarding this issue, I tried renewing the credentials but still same exception:

    Upload failed: org.jenkinsci.plugins.googleplayandroidpublisher.UploadException: java.security.GeneralSecurityException: Unable to retrieve an access token with the provided credentials
    at org.jenkinsci.plugins.googleplayandroidpublisher.CredentialsHandler.getServiceAccountCredentials(CredentialsHandler.java:60)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.perform(ApkPublisher.java:301)
    at hudson.tasks.BuildStepMonitor$2.perform(BuildStepMonitor.java:32)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:764)
    at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:724)
    at hudson.model.Build$BuildExecution.post2(Build.java:185)
    at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:671)
    at hudson.model.Run.execute(Run.java:1769)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
    at hudson.model.ResourceController.execute(ResourceController.java:98)
    at hudson.model.Executor.run(Executor.java:374)
    Caused by: java.security.GeneralSecurityException: Unable to retrieve an access token with the provided credentials
    at com.google.jenkins.plugins.credentials.oauth.RemotableGoogleCredentials.<init>(RemotableGoogleCredentials.java:70)
    at com.google.jenkins.plugins.credentials.oauth.GoogleRobotCredentials.forRemote(GoogleRobotCredentials.java:204)
    at org.jenkinsci.plugins.googleplayandroidpublisher.CredentialsHandler.getServiceAccountCredentials(CredentialsHandler.java:36)
    ... 10 more
    Caused by: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
    {
    "error" : "invalid_grant",
    "error_description" : "Invalid JWT: Token must be a short-lived token and in a reasonable timeframe"
    }
    at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
    at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
    at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
    at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
    at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
    at com.google.jenkins.plugins.credentials.oauth.RemotableGoogleCredentials.<init>(RemotableGoogleCredentials.java:64)
    ... 12 more

  7. Can upload the same APK file manually to the Google Dev console Alpha channel, but not via the plugin. This is the console log from Jenkins.

    Authenticating to Google Play API...

    • Credential: Dev Console Publishing
    • Application ID: com.xxx.yyy
      Uploading 1 APK(s) with application ID: com.xxx.yyy

    APK file: 1717.apk
    SHA-1 hash: 3608212d8b1e073a43f620798c722e8857f9db10
    versionCode: 1717
    minSdkVersion: 16

    Upload failed: APK is not zip aligned.

    I also made sure that the apk was zip aligned.

    1. I'd recommend getting in touch with Google Play Developer Support about that.

      I don't think there's much I will be able to do about this, but feel free to open an issue and attach the problematic APK, and I can take a look.

  8. Hi I am getting below error continuously while uploading apk to play store. Its a Xamarin Cross platform app.

    Should i go ahead and create a bug for this? Because existing bug has been closed ( JENKINS-33689 - Getting issue details... STATUS )

     

    Uploading 1 APK(s) with application ID: com.company.appName
    APK file: com.company.appName\com.company.appName.Droid\bin\Release\com.company.appName-Released.apk
    SHA-1 hash: e0a6e9f43993181222b65fc14044be49601f3787
    versionCode: 13
    minSdkVersion: 15

    Upload failed: org.jenkinsci.plugins.googleplayandroidpublisher.PublisherApiException: com.google.api.client.googleapis.json.GoogleJsonResponseException: 500 Internal Server Error
    {
    "code" : 500,
    "message" : null
    }
    at org.jenkinsci.plugins.googleplayandroidpublisher.AbstractPublisherTask.call(AbstractPublisherTask.java:34)
    at hudson.remoting.UserRequest.perform(UserRequest.java:120)
    at hudson.remoting.UserRequest.perform(UserRequest.java:48)
    at hudson.remoting.Request$2.run(Request.java:326)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at hudson.remoting.Engine$1$1.run(Engine.java:62)
    at java.lang.Thread.run(Unknown Source)
    at ......remote call to xxx-xxx-xxx(Native Method)
    at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1416)
    at hudson.remoting.UserResponse.retrieve(UserRequest.java:252)
    at hudson.remoting.Channel.call(Channel.java:781)
    at hudson.FilePath.act(FilePath.java:1074)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.perform(ApkPublisher.java:303)
    at hudson.tasks.BuildStepMonitor$2.perform(BuildStepMonitor.java:32)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:782)
    at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:723)
    at hudson.model.Build$BuildExecution.post2(Build.java:185)
    at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:668)
    at hudson.model.Run.execute(Run.java:1763)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
    at hudson.model.ResourceController.execute(ResourceController.java:98)
    at hudson.model.Executor.run(Executor.java:410)
    Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 500 Internal Server Error
    {
    "code" : 500,
    "message" : null
    }
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:423)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkUploadTask.execute(ApkUploadTask.java:109)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkUploadTask.execute(ApkUploadTask.java:34)
    at org.jenkinsci.plugins.googleplayandroidpublisher.AbstractPublisherTask.call(AbstractPublisherTask.java:31)
    at hudson.remoting.UserRequest.perform(UserRequest.java:120)
    at hudson.remoting.UserRequest.perform(UserRequest.java:48)
    at hudson.remoting.Request$2.run(Request.java:326)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at hudson.remoting.Engine$1$1.run(Engine.java:62)
    at java.lang.Thread.run(Unknown Source)

    - No changes have been applied to the Google Play account
    Build step 'Upload Android APK to Google Play' marked build as failure

  9. Hi, first, thanks for this great plugin. Im using this plugin as a step in my pipeline and im successfully uploading an apk to the alpha track. The problem is with the release notes which are not uploaded even though the list was provided. This is my sample step:

    androidApkUpload apkFilesPattern: '****************',
                                   googleCredentialsId: '***************',
                                   trackName: 'alpha'
                                   recentChangeList: [
                                       [language: 'en-US', text: "${releaseNotes.'en-US'}"],
                                       [language: 'de-DE', text: "${releaseNotes.'de-DE'}"],
                                       [language: 'es-ES', text: "${releaseNotes.'es-ES'}"],
                                       [language: 'fr-FR', text: "${releaseNotes.'fr-FR'}"],
                                       [language: 'it-IT', text: "${releaseNotes.'it-IT'}"],
                                       [language: 'ja-JP', text: "${releaseNotes.'ja-JP'}"],
                                       [language: 'ko-KR', text: "${releaseNotes.'ko-KR'}"],
                                       [language: 'pt-BR', text: "${releaseNotes.'pt-BR'}"],
                                       [language: 'pt-BR', text: "${releaseNotes.'pt-BR'}"],
                                       [language: 'ru-RU', text: "${releaseNotes.'ru-RU'}"],
                                       [language: 'zh-CN', text: "${releaseNotes.'zh-CN'}"],
                                       [language: 'zh-TW', text: "${releaseNotes.'zh-TW'}"]
                                   ]

    Also tried to send only one lang with hardcoed text, again without any success. Any suggestions?

     

    1. I was missing a comma after the trackName paramater.

  10. Hi there,

    Using the the move apk to a different release track job the recent changes field doesn't copy across.

    I am using the read version codes from the apk option.

    Is there anything that can be done get around this, or should issue a bug 

    Cheers.

    1. As far as I'm aware, and according to the API, release notes are tied to an APK versionCode, so they should remain associated with the APK, even when you move an APK between release tracks.

      You could try contacting Google Play Developer support to see whether this is a bug.

  11. Hi

    how can I solve this error

    ERROR: Build step failed with exception
    java.lang.NullPointerException
    at org.jenkinsci.plugins.googleplayandroidpublisher.Util.getPublisherErrorMessage(Util.java:97)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.publishApk(ApkPublisher.java:383)
    at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.perform(ApkPublisher.java:198)
    at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:78)
    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
    at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:720)
    at hudson.model.Build$BuildExecution.post2(Build.java:186)
    at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:665)
    at hudson.model.Run.execute(Run.java:1753)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
    at hudson.model.ResourceController.execute(ResourceController.java:98)
    at hudson.model.Executor.run(Executor.java:405)
    Build step 'Upload Android APK to Google Play' marked build as failure
    [BFA] Scanning build for known causes...
    [BFA] Found failure cause(s):
    [BFA] COMPILATION ERROR
    [BFA] Done. 0s
    Notifying upstream projects of job completion
    Finished: FAILURE

    1. Thanks for reporting this. Google Play is saying that your APK(s) can't be published due to an error, but the Jenkins plugin is failing to parse the error message.

      To solve this you can either:

      • figure out why your APKs are being rejected and fix that problem, or
      • wait for this bug to be fixed in  JENKINS-49789 - Getting issue details... STATUS
      1. I published the apk manually without errors.

        I don't understand why the apk is broken if I use this plug in.

        Thanks

        1. Heh.. ok.  The Google Play API is sometimes unreliable, so maybe it was just a temporary issue.

          Thanks for the feedback!

          1. I did not solve this issue. if I upload directly my apk (in google play console) I don't have problems.

            with jenkins is impossible

            Thanks

  12. Hi Christopher,

    This is my setting:

    androidApkUpload apkFilesPattern: 'app/build/outputs/apk/samplePaid/release/**.apk',
    googleCredentialsId: 'jenkins-to-alpha', recentChangeList: [[language: 'ru-RU', text: "Build v${BUILD_NUMBER}."]],
    rolloutPercentage: '100%', trackName: 'alpha'

    Thanks for the plugin – everything is great.

    Recently, I added the possibility of uploading deobfuscation files. Now my setting looks this way:

    androidApkUpload apkFilesPattern: 'app/build/outputs/apk/samplePaid/release/**.apk',
    deobfuscationFilesPattern: 'app/build/outputs/mapping/samplePaid/release/mapping.txt',
    googleCredentialsId: 'jenkins-to-alpha', recentChangeList: [[language: 'ru-RU', text: "Build v${BUILD_NUMBER}."]],
    rolloutPercentage: '100%', trackName: 'alpha'

    This is my log:

    00:51:44 Uploading 4 APK(s) with application ID: com.example.sample
    00:51:44
    00:51:44 APK file: app/build/outputs/apk/samplePaid/release/samplePaidRelease-arm64-v8a-3000002-1.0.0-arm64-v8a-9406e898.apk
    00:51:44 SHA-1 hash: 53fb8087447da7904f8e0728e38575a0abdb625d
    00:51:44 versionCode: 3000002
    00:51:44 minSdkVersion: 16
    00:51:48 Uploading associated ProGuard mapping file: app/build/outputs/mapping/samplePaid/release/mapping.txt

    ...

    00:52:11 Assigning APK(s) to alpha release track...
    00:52:11 The alpha release track will now contain APK(s) with version code(s): 1000002, 2000002, 3000002, 6000002
    00:52:11 
    00:52:12 Applying changes to Google Play...
    00:52:15 Changes were successfully applied to Google Play

    No error or warning is shown here but there are no deobfuscation file(s) is Google Developer Console.

    What do you think can be the problem?

    Thanks,
    Savelii

    1. It seems that Google Play broke this functionality in the past few weeks — please contact Google Play Developer Support by chat or email and ask them to fix this.

      See also the discussion at the bottom:  JENKINS-38731 - Getting issue details... STATUS

  13. Hi,

    We currently can’t reach out due to firewall rules, we are not wanting to go through a proxy but to open in/outbound rules. What is the https URL:Port i would need to have opened.

    Thanks

    1. You'd have to try it out, or check the source code of Google's "google-api-services-androidpublisher" library and its dependent "google-api-client" library that the plugin uses to get a definitive answer, but I believe likely just these two hostnames are involved, with all URLs being regular https://:

      • accounts.google.com
      • www.googleapis.com
    2. Dear Darren,


      We struggling with the same problem. Could you fix the problem?


      Thanks, 

      Peter

  14. Hi,

    Is there a way to use "release track" for "internal test" ? It's a new feature/track from Play Store to increase speed test app

    Documentation saids "Assigning apps to alpha, beta or production release tracks" with value "alpha", "beta" or "production"

    Thanks

    1. There was a Pull Request opened a couple of days ago to add support for this: https://github.com/jenkinsci/google-play-android-publisher-plugin/pull/8

      So this functionality should be in the next release.

  15. Hello,

    I'm trying to upload APK to Internal test and its failing with below error. Are the supported release tracks are only alpha,beta,production?

    Cannot upload to Google Play:
    - 'internal test' is not a valid release track
  16. Hi Christopher,

    Thanks very much for writing this plugin. Just noticed one functionality that has me worried before rolling out to prod. It seems that when I am re-executing a move from Beta to Prod with an increased rollout percentage, it lists all the current APKs in production and prints a statement that it is going to delete all of them. This is scary as we retain a lot of old apks to support older api levels/devices etc. I believe the correct functionality should be to only remove the version code that matches with the rollout apk and remove that from the rolloutTrack. Please let me know if I am doing something wrong and whether this is how the ramp up works.

    1. // If there's an existing rollout, we need to clear it out so a new production/rollout APK can be added
      
                  final Track rolloutTrack = fetchTrack(ROLLOUT);
      
                  if (rolloutTrack != null) {
      
                      logger.println(String.format("Removing existing staged rollout APK(s): %s",
      
                              join(rolloutTrack.getVersionCodes(), ", ")));
      
                      rolloutTrack.setVersionCodes(null);
      
                      editService.tracks().update(applicationId, editId, rolloutTrack.getTrack(), rolloutTrack).execute();
      
                  }
      
      
      
      

      This is the part of the code that I am referring to.

  17. Hello,

    How can I read recent changes text from a file in the repo ? I'm using free style job.

    My Master is on Linux and Worker is on Windows.

     

  18. Hello,

    I'm trying the 1.8 version, but the google service credentials are not working when they are stored in Folders. I can't store the credential in root, because it's restricted by the jenkins admin.

  19. We are using unity split architecture option that creates 3 different apk's and a single obb, I'd like this obb to be uploaded and used for all 3 apks and I'd prefer to not have to copy the obb twice and rename it.

    Can we specify a random obb file with any name to be uploaded for all 3 apks, since unity changes the version codes of the apk's it produces it'd be nice if we just relied on google play doing the obb renaming for us and not having to have a matching file name for this plugin.

  20. Any plans to support the new Android App Bundle's format when pushing from Jenkins to the Google Play Store?

  21. Is there any plan for App Bundle format upload from Jenkins to Google Play?

  22. Hi,

    Today, I used this plugin inside docker and tried to upload the android signed apk file to playstore. But the job failed with the following exception, Could anyone help me in fixing this issue? 

    21:36:19 Authenticating to Google Play API...
    21:36:19 - Credential: xxxxxx
    21:36:19 - Application ID: xxxx.xxxx.xxxxx.xxxxx
    21:36:19
    21:36:21 ERROR: Build step failed with exception
    21:36:21 java.lang.NullPointerException
    21:36:21 at org.jenkinsci.plugins.googleplayandroidpublisher.ApkUploadTask.execute(ApkUploadTask.java:82)
    21:36:21 at org.jenkinsci.plugins.googleplayandroidpublisher.ApkUploadTask.execute(ApkUploadTask.java:33)
    21:36:21 at org.jenkinsci.plugins.googleplayandroidpublisher.AbstractPublisherTask.call(AbstractPublisherTask.java:33)
    21:36:21 at hudson.FilePath.act(FilePath.java:1163)
    21:36:21 at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.publishApk(ApkPublisher.java:375)
    21:36:21 at org.jenkinsci.plugins.googleplayandroidpublisher.ApkPublisher.perform(ApkPublisher.java:195)
    21:36:21 at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:81)
    21:36:21 at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
    21:36:21 at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:744)
    21:36:21 at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:690)
    21:36:21 at hudson.model.Build$BuildExecution.post2(Build.java:186)
    21:36:21 at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:635)
    21:36:21 at hudson.model.Run.execute(Run.java:1835)
    21:36:21 at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
    21:36:21 at hudson.model.ResourceController.execute(ResourceController.java:97)
    21:36:21 at hudson.model.Executor.run(Executor.java:429)
    21:36:21 Build step 'Upload Android APK to Google Play' marked build as failure

    1. Hi,

      I tried once again now, and looks working fine without any changes, seems restart of my machine fixed this issue.

  23. Has anybody successfully been able to move an APK between tracks and have the Release Notes go with it?  When I use androidApkMove, it will properly move the APK, but the release notes don't get moved with it.  Without this, I can't use the plugin, hopefully somebody has seen this and knows how to fix it.  I've opened a Bug and SO post, nothing going on either of them yet though.

    https://issues.jenkins-ci.org/browse/JENKINS-54479

    https://stackoverflow.com/questions/53166082/jenkins-google-play-android-publisher-plugin-androidapkmove-not-moving-release-n

    1. I had this issue a while ago as well, couldn't get around it without rebuilding with my own version of the plugin. 
      here is the old pull request maybe it can help you https://github.com/jenkinsci/google-play-android-publisher-plugin/pull/7