GPP is Android's unofficial release automation Gradle Plugin. It can do anything from building, uploading, and then promoting your App Bundle or APK to publishing app listings and other metadata.

Overview

Logo

Gradle Play Publisher

Gradle Play Publisher is Android's unofficial release automation Gradle Plugin. It can do anything from building, uploading, and then promoting your App Bundle or APK to publishing app listings and other metadata.

Table of contents

  1. Quickstart guide
  2. Prerequisites
    1. Initial Play Store upload
    2. Signing configuration
    3. Service Account
  3. Basic setup
    1. Installation
    2. Authenticating Gradle Play Publisher
  4. Task organization
  5. Managing artifacts
    1. Common configuration
    2. Publishing an App Bundle
    3. Publishing APKs
    4. Uploading an Internal Sharing artifact
    5. Promoting artifacts
    6. Handling version conflicts
  6. Managing Play Store metadata
    1. Quickstart
    2. Directory structure
    3. Publishing listings
    4. Publishing in-app products
  7. Working with product flavors
    1. Disabling publishing
    2. Combining artifacts into a single release
    3. Using multiple Service Accounts
  8. Advanced topics
    1. Using CLI options
    2. Using HTTPS proxies

Quickstart guide

  1. Upload the first version of your APK or App Bundle using the Google Play Console
  2. Create a Google Play Service Account
  3. Sign your release builds with a valid signingConfig
  4. Add and apply the plugin
  5. Authenticate GPP

Prerequisites

Initial Play Store upload

The first APK or App Bundle needs to be uploaded via the Google Play Console because registering the app with the Play Store cannot be done using the Play Developer API. For all subsequent uploads and changes, GPP may be used.

Signing configuration

To successfully upload apps to the Play Store, they must be signed with your developer key. Make sure you have a valid signing configuration.

Service Account

To use GPP, you must create a service account with access to the Play Developer API:

  1. If you don't already have one, create a GCP project for your app(s)
  2. Enable the AndroidPublisher API for that GCP project
  3. Link your Google Play developer account to your GCP project
  4. Create a service account and key
    1. Make sure you're in the GCP project you used above (check the project query param in the URL)
    2. Select New service account
    3. Give it a name and the Project Owner role (don't worry, we'll remove this later)
    4. Leave JSON checked
  5. Move the downloaded JSON credentials into your project and tell GPP about it
  6. Give your service account permissions to publish apps on your behalf
    1. Click Invite new user
    2. Copy/paste the service account email (you can find it in the JSON credentials)
    3. Don't touch the roles
    4. Specify which apps the service account should have access to. In this example, GPP has full access to testing tracks and app listings, but will be unable to make production releases: Minimum Service Account permissions
  7. Run ./gradlew bootstrap or some other GPP task to validate your setup
  8. Now that you've successfully created the connection between GCP and Google Play, you can remove the Project Owner persmissions
    1. Go to your IAM settings
    2. Search for the service account you created
    3. Click the edit icon (found at the end of the row)
    4. In the permission selection panel that opens, click the trash icon to remove the owner role
    5. Click save

Basic setup

Installation

Apply the plugin to each individual com.android.application module where you want to use GPP through the plugins {} DSL:

Kotlin
plugins {
    id("com.android.application")
    id("com.github.triplet.play") version "3.3.0"
}
Groovy
plugins {
    id 'com.android.application'
    id 'com.github.triplet.play' version '3.3.0'
}

Snapshot builds

If you're prepared to cut yourself on the bleeding edge of GPP development, snapshot builds are available from Sonatype's snapshots repository:

Kotlin
buildscript {
    repositories {
        // ...
        maven("https://oss.sonatype.org/content/repositories/snapshots")
    }

    dependencies {
        // ...
        classpath("com.github.triplet.gradle:play-publisher:3.4.0-SNAPSHOT")
    }
}
Groovy
buildscript {
    repositories {
        // ...
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
    }

    dependencies {
        // ...
        classpath 'com.github.triplet.gradle:play-publisher:3.4.0-SNAPSHOT'
    }
}

Authenticating Gradle Play Publisher

After you've gone through the Service Account setup, you should have a JSON file with your private key. Add a play block alongside your android one with the file's location:

android { ... }

play {
    serviceAccountCredentials.set(file("your-key.json"))
}

Note: If you commit unencrypted Service Account keys to source, you run the risk of letting anyone access your Google Play account. To circumvent this issue, put the contents of your JSON file in the ANDROID_PUBLISHER_CREDENTIALS environment variable and don't specify the serviceAccountCredentials property.

Task organization

GPP follows the Android Gradle Plugin's naming convention: [action][Variant][Thing]. For example, publishPaidReleaseBundle will be generated if have a paid product flavor.

Lifecycle tasks to publish multiple product flavors at once are also available. For example, publishBundle publishes all variants.

To find available tasks, run ./gradlew tasks --group publishing and use ./gradlew help --task [task] where task is something like publishBundle to get more detailed documentation for a specific task.

Managing artifacts

GPP supports uploading both the App Bundle and APK. Once uploaded, GPP also supports promoting those artifacts to different tracks.

Common configuration

Several options are available to customize how your artifacts are published:

  • track is the target stage for an artifact, i.e. internal/alpha/beta/production or any custom track
    • Defaults to internal
  • releaseStatus is the type of release, i.e. ReleaseStatus.[COMPLETED/DRAFT/HALTED/IN_PROGRESS]
    • Defaults to ReleaseStatus.COMPLETED
  • userFraction is the percentage of users who will receive a staged release
    • Defaults to 0.1 aka 10%
    • Note: the userFraction is only applicable where releaseStatus=[IN_PROGRESS/HALTED]
  • updatePriority sets the update priority for a new release. See Google's documentation on consuming this value.
    • Defaults to the API value

Example configuration:

import com.github.triplet.gradle.androidpublisher.ReleaseStatus

play {
    // Overrides defaults
    track.set("production")
    userFraction.set(0.5)
    updatePriority.set(2)
    releaseStatus.set(ReleaseStatus.IN_PROGRESS)

    // ...
}

Uploading release notes

While GPP can automatically build and find your artifact, you'll need to tell the plugin where to find your release notes.

Add a file under src/[sourceSet]/play/release-notes/[language]/[track].txt where sourceSet is a full variant name, language is one of the Play Store supported codes, and track is the channel you want these release notes to apply to (or default if unspecified).

As an example, let's assume you have these two different release notes:

src/main/play/release-notes/en-US/default.txt
.../beta.txt

When you publish to the beta channel, the beta.txt release notes will be uploaded. For any other channel, default.txt will be uploaded.

Note: the Play Store limits your release notes to a maximum of 500 characters.

Uploading developer facing release names

The Play Console supports customizing release names. These aren't visible to users, but may be useful for internal processes. Similar to release notes, release names may be specified by placing a [track].txt file in the release-names directory under your play folder. For example, here's a custom release name for the alpha track in the play/release-names/alpha.txt file:

My custom release name

If it makes more sense to specify the release name in your build script, the releaseName property is available:

play {
    // ...
    releaseName.set("My custom release name")
}

Note: the play.releaseName property takes precedence over the resource files.

There is also a --release-name CLI option for quick access. For example, ./gradlew publishBundle --release-name "Hello World!".

Note: the Play Store limits your release names to a maximum of 50 characters.

Uploading a pre-existing artifact

By default, GPP will build your artifact from source. In advanced use cases, this might not be the desired behavior. For example, if you need to inject translations into your APK or App Bundle after building it but before publishing it. Or perhaps you simply already have an artifact you wish to publish. GPP supports this class of use cases by letting you specify a directory in which publishable artifacts may be found:

play {
    // ...
    artifactDir.set(file("path/to/apk-or-app-bundle/dir"))
}

For quick access, you can also use the --artifact-dir CLI option:

./gradlew publishBundle --artifact-dir path/to/app-bundle/dir

Note: all artifacts in the specified directory will be published.

Uploading mapping files

Note: mapping files aren't applicable to App Bundles since the mapping file is contained within the bundle.

By default, GPP will look for a file called mapping.txt in your artifact directory. If you need more granularity, you can prefix mapping.txt with your APK file name. For example:

artifact-dir/
├── mapping.txt
├── my-first-app.apk
├── my-second-app.apk
└── my-second-app.mapping.txt

my-second-app.apk will use my-second-app.mapping.txt and my-first-app.apk will use the default mapping.txt because no specific mapping file was specified.

Retaining artifacts

GPP supports keeping around old artifacts such as OBB files or WearOS APKs:

play {
    // ...
    retain {
        artifacts.set(listOf(123)) // Old APK version code
        mainObb.set(123) // Old main OBB version code
        patchObb.set(123) // Old patch OBB version code
    }
}

Publishing an App Bundle

Run ./gradlew publishBundle.

Defaulting to the App Bundle

You'll notice that if you run ./gradlew publish, it uploads an APK by default. To change this, default to the App Bundle:

play {
    // ...
    defaultToAppBundles.set(true)
}

Publishing APKs

Run ./gradlew publishApk. Splits will be uploaded if available.

Uploading an Internal Sharing artifact

Run ./gradlew uploadReleasePrivateBundle for App Bundles and ./gradlew uploadReleasePrivateApk for APKs. To upload an existing artifact, read about how to do so.

Retrieving the download URL

After running an Internal Sharing task, the output of the API response will be stored in the following directory: build/outputs/internal-sharing/[bundle/apk]/[variant]/. Each file will be named [apk/aab name].json.

For example, here are the contents of app/build/outputs/internal-sharing/bundle/release/app-release.json:

{
    "certificateFingerprint": "...",
    "downloadUrl": "...",
    "sha256": "..."
}

Installing Internal Sharing artifacts

To accelerate development, GPP supports uploading and then immediately installing Internal Sharing artifacts. This is similar to the AGP's install[Variant] task.

Run ./gradlew installReleasePrivateArtifact to install an artifact built on-the-fly and ./gradlew uploadReleasePrivateBundle --artifact-dir path/to/artifact installReleasePrivateArtifact to install an existing artifact.

Promoting artifacts

Existing releases can be promoted and/or updated to the configured track with ./gradlew promoteArtifact.

By default, the track from which to promote a release is determined by the most unstable channel that contains a release. Example: if the alpha channel has no releases, but the beta and prod channels do, the beta channel will be picked. To configure this manually, use the fromTrack property:

play {
    // ...
    fromTrack.set("alpha")
}

Similarly, the track to which to promote a release defaults to the promoteTrack property. If unspecified, the resolved fromTrack property will be used instead and an in-place update will be performed. Example configuration:

play {
    // ...
    promoteTrack.set("beta")
}

If you need to execute a one-time promotion, you can use the CLI args. For example, this is how you would promote an artifact from the alpha ➡️ beta track with only 25% of users getting the release:

./gradlew promoteArtifact \
  --from-track alpha --promote-track beta \
  --release-status inProgress --user-fraction .25

Finishing a rollout

If you have an ongoing inProgress release and would like to perform a full rollout, simply change the release status to completed. A user fraction of 1.0 is invalid and will be rejected.

Handling version conflicts

If an artifact already exists with a version code greater than or equal to the one you're trying to upload, an error will be thrown when attempting to publish the new artifact. You have two options:

  • Ignore the error and continue (ResolutionStrategy.IGNORE)
  • Automatically pick the correct version code so you don't have to manually update it (ResolutionStrategy.AUTO)

Example configuration:

import com.github.triplet.gradle.androidpublisher.ResolutionStrategy

play {
    // ...
    resolutionStrategy.set(ResolutionStrategy.IGNORE)
}

Post-processing outputs sanitized by auto resolution

For example, you could update you app's version name based on the new version code:

import com.github.triplet.gradle.androidpublisher.ResolutionStrategy

play {
    // ...
    resolutionStrategy.set(ResolutionStrategy.AUTO)
}

android {
  onVariantProperties {
    for (output in outputs) {
      val processedVersionCode = output.versionCode.map { playVersionCode ->
        // Do something to the version code...
        // In this example, version names will look like `myCustomVersionName.123`
        "myCustomVersionName.$playVersionCode"
      }

      output.versionName.set(processedVersionCode)
    }
  }
}

Managing Play Store metadata

GPP supports uploading any metadata you might want to change with each release, from screenshots and descriptions to in-app purchases and subscriptions.

Quickstart

GPP includes a bootstrap task that pulls down your existing listing and initializes everything for you. To use it, run ./gradlew bootstrap.

Note: if you have a pre-existing play folder, it will be reset.

Directory structure

GPP follows the Android Gradle Plugin's source set guidelines and priorities. src/[sourceSet]/play is the base directory for Play Store metadata. Since main is the most common source set, it will be assumed in all following examples.

In addition to merging metadata across variants, GPP merges translations. That is, if a resources is provided in a default language such as en-US but not in fr-FR, the resource will be copied over when uploading French metadata.

Publishing listings

Run ./gradlew publishListing.

Uploading global app metadata

Base directory: play

File Description
contact-email.txt Developer email
contact-phone.txt Developer phone
contact-website.txt Developer website
default-language.txt The default language for both your Play Store listing and translation merging as described above

Uploading text based listings

Base directory: play/listings/[language] where language is one of the Play Store supported codes

File Description Character limit
title.txt App title 50
short-description.txt Tagline 80
full-description.txt Full description 4000
video-url.txt Youtube product video N/A

Uploading graphic based listings

Directory: play/listings/[language]/graphics where language is defined as in the previous section

Image files are organized a bit differently than in previous sections. Instead of the file name, the parent directory's name is used as the media type. This is because multiple images may be provided for the same media type. While file names are arbitrary, they will be uploaded in alphabetical order and presented on the Play Store as such. Therefore, we recommend using a number as the file name (1.png for example). Both PNG and JPEG images are supported.

Directory Max # of images Image dimension constraints (px)
icon 1 512x512
feature-graphic 1 1024x500
phone-screenshots 8 [320..3840]x[320..3840]
tablet-screenshots 8 [320..3840]x[320..3840]
large-tablet-screenshots 8 [320..3840]x[320..3840]
tv-banner 1 1280x720
tv-screenshots 8 [320..3840]x[320..3840]
wear-screenshots 8 [320..3840]x[320..3840]

Publishing in-app products

Run ./gradlew publishProducts.

Manually setting up in-app purchase files is not recommended. Bootstrap them instead with ./gradlew bootstrap --products.

Working with product flavors

When working with product flavors, granular configuration is key. GPP provides varying levels of granularity to best support your needs, all through the playConfigs block:

Kotlin
play {
    // In a simple app, this play block is all you'll need. However, in an app with product flavors,
    // the play block becomes a place to store default configurations. Anything configured in here
    // will apply to all product flavors, that is, unless an override is supplied in the playConfigs
    // block.
}

android {
    // Suppose we have the following flavors
    flavorDimensions("customer", "type")
    productFlavors {
        register("firstCustomer") { setDimension("customer") }
        register("secondCustomer") { setDimension("customer") }

        register("demo") { setDimension("type") }
        register("full") { setDimension("type") }
    }

    playConfigs {
        // Now, we can configure GPP however precisely is required.

        // Configuration overrides occur in a cascading manner from most to least specific. That is,
        // a property configured in a build type + flavor combo overrides that same property
        // configured in a flavor combo, which overrides a build type combo, which in turn overrides
        // the play block. Properties not configured are inherited.
        register("firstCustomerFullRelease") { ... } // Build type + flavor
        register("firstCustomer") { ... } // Flavor
        register("release") { ... } // Build type
    }
}
Groovy
play {
    // In a simple app, this play block is all you'll need. However, in an app with product flavors,
    // the play block becomes a place to store default configurations. Anything configured in here
    // will apply to all product flavors, that is, unless an override is supplied in the playConfigs
    // block.
}

android {
    // Suppose we have the following flavors
    flavorDimensions 'customer', 'type'
    productFlavors {
        firstCustomer { dimension 'customer' }
        secondCustomer { dimension 'customer' }

        demo { dimension 'type' }
        full { dimension 'type' }
    }

    playConfigs {
        // Now, we can configure GPP however precisely is required.

        // Configuration overrides occur in a cascading manner from most to least specific. That is,
        // a property configured in a build type + flavor combo overrides that same property
        // configured in a flavor combo, which overrides a build type combo, which in turn overrides
        // the play block. Properties not configured are inherited.
        firstCustomerFullRelease { ... } // Build type + flavor
        firstCustomer { ... } // Flavor
        release { ... } // Build type
    }
}

Disabling publishing

Sometimes, you may not want to publish all variants of your app. Or maybe you don't want publishing enabled on CI or local dev machines. Whatever the case may be, GPP can be disabled with the enabled property:

Kotlin
android {
    // ...

    playConfigs {
        register("myCustomVariantOrProductFlavor") {
            enabled.set(true)
        }

        // ...
    }
}

play {
    enabled.set(false) // This disables GPP by default. It could be the other way around.
    // ...
}
Groovy
android {
    // ...

    playConfigs {
        myCustomVariantOrProductFlavor {
            enabled.set(true)
        }

        // ...
    }
}

play {
    enabled.set(false) // This disables GPP by default. It could be the other way around.
    // ...
}

Combining artifacts into a single release

By default, GPP assumes every product flavor consists of a separate, independent app. To tell GPP this isn't the case, you must use the commit property:

Kotlin
android {
    // ...

    playConfigs {
        register("someFlavor1") {
            commit.set(false)
        }

        register("someFlavor[2..N)") {
            commit.set(false)
        }

        register("someFlavorN") {
            // This isn't actually needed since the default is true. Here's what you *do* need:
            // 1. A starter no-commit variant (someFlavor1 in this case)
            // 2. (Optional) Intermediate no-commit variants (someFlavor2, someFlavor3, ...)
            // 3. One finisher variant to commit (aka do NOT mark someFlavorN as no-commit)
            commit.set(true)
        }

        // ...
    }
}

afterEvaluate {
    // Now make sure the tasks execute in the right order
    val intermediateTasks = listOf(
            "publishSomeFlavor2Release[Apk/Bundle]",
            "publishSomeFlavor3Release[Apk/Bundle]",
            ...
    )
    tasks.matching { it.name in intermediateTasks }.configureEach {
        mustRunAfter("publishSomeFlavor1Release[Apk/Bundle]")
    }
    tasks.named("publishSomeFlavorNRelease[Apk/Bundle]").configure {
        mustRunAfter(intermediateTasks)
    }
}
Groovy
android {
    // ...

    playConfigs {
        someFlavor1 {
            commit.set(false)
        }

        someFlavor[2..N) {
            commit.set(false)
        }

        someFlavorN {
            // This isn't actually needed since the default is true. Here's what you *do* need:
            // 1. A starter no-commit variant (someFlavor1 in this case)
            // 2. (Optional) Intermediate no-commit variants (someFlavor2, someFlavor3, ...)
            // 3. One finisher variant to commit (aka do NOT mark someFlavorN as no-commit)
            commit.set(true)
        }

        // ...
    }
}

afterEvaluate {
    // Now make sure the tasks execute in the right order
    def intermediateTasks = [
            "publishSomeFlavor2Release[Apk/Bundle]",
            "publishSomeFlavor3Release[Apk/Bundle]",
            ...
    ]
    tasks.matching { intermediateTasks.contains(it.name) }.configureEach {
        mustRunAfter("publishSomeFlavor1Release[Apk/Bundle]")
    }
    tasks.named("publishSomeFlavorNRelease[Apk/Bundle]").configure {
        mustRunAfter(intermediateTasks)
    }
}

Using multiple Service Accounts

If you need to publish each build flavor to a separate Play Store account, simply provide separate credentials per product flavor.

Kotlin
android {
    // ...

    playConfigs {
        register("firstCustomer") {
            serviceAccountCredentials.set(file("customer-one-key.json"))
        }

        register("secondCustomer") {
            serviceAccountCredentials.set(file("customer-two-key.json"))
        }
    }
}
Groovy
android {
    // ...

    playConfigs {
        firstCustomer {
            serviceAccountCredentials.set(file('customer-one-key.json'))
        }

        secondCustomer {
            serviceAccountCredentials.set(file('customer-two-key.json'))
        }
    }
}

Advanced topics

Using CLI options

All configuration options available in the play block are also available as CLI options so you don't have to update your build file when making one-time changes. For example, to configure play.track on demand, use the --track option. camelCase options are converted to kebab-case ones.

To get a list of options and their quick documentation, use ./gradlew help --task [task] where task is something like publishBundle.

Using HTTPS proxies

If you need to use GPP behind an HTTPS-proxy, but it fails with an SSLHandshakeException, you can provide your own truststore via the javax.net.ssl.trustStore property in your project's gradle.properties:

systemProp.javax.net.ssl.trustStore=/path/to/your/truststore.ks
systemProp.javax.net.ssl.trustStorePassword=YourTruststorePassword

GPP will automatically pick it up and use your proxy.

Comments
  • Support combining multiple drafts into a single release

    Support combining multiple drafts into a single release

    In projects with multiple modules (Eg: mobile and wear) publishRelease will fail due to the following error:

    om.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
      {
        "code" : 403,
        "errors" : [ {
          "domain" : "androidpublisher",
          "message" : "You cannot rollout this release because it does not allow any existing users to upgrade to the newly added APKs.",
          "reason" : "apkNoUpgradePaths"
        } ],
        "message" : "You cannot rollout this release because it does not allow any existing users to upgrade to the newly added APKs."
      }
    

    I believe that's because each APK is creating its own release, hence the second upload will fail with the above message.

    Ideally publishRelease should create a multiple APK release.

    Thank you!

    bug enhancement 
    opened by alrosot 39
  • publishApk task fails with NoSuchMethodError: AbstractGoogleJsonClient$Builder.setBatchPath after updating to 1.2.2

    publishApk task fails with NoSuchMethodError: AbstractGoogleJsonClient$Builder.setBatchPath after updating to 1.2.2

    publishApkBrandStoreRelease task fails with

    java.lang.NoSuchMethodError: com.google.api.client.googleapis.services.json.AbstractGoogleJsonClient$Builder
    .setBatchPath(Ljava/lang/String;)Lcom/google/api/client/googleapis/services/AbstractGoogleClient$Builder;
    

    After we updated the plugin to 1.2.2 from 1.2.0. We reverted back to 1.2.0 for now.

    Our project has multiple dimensions in the following order: brand, store, buildType. Example variant: FooPlaystoreRelease.

    opened by Nimrodda 29
  • New Android App Bundle

    New Android App Bundle

    opened by thelittlefireman 29
  • Tracks and user fraction

    Tracks and user fraction

    Good day, I wanted to know more about usage of GPP

    1. Does userFraction applies to all tracks even in internal track?
    2. What does the releaseStatus COMPLETED and IN_PROGRESS means?

    Thank you

    enhancement docs feature:other 
    opened by ArcherEmiya05 24
  • 403 Permission denied :/

    403 Permission denied :/

    Hi, Im using version 2.8.0.

    I'm trying to setup gpp in a project, which was not new. I successfully used gpp without a problem in previous projects. However now I keep getting 403 Permission denied.

    I get that it's most likely service account setup wrongly, however I have 0 clues left as what could I have done wrong as I followed your guide, and various guides on internet as well, and visually it checks out but yet

    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':generateEditForSkDotTmDotMobile'.
    > A failure occurred while executing com.github.triplet.gradle.play.tasks.GenerateEdit$Generator
       > 403 Forbidden
         POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/sk.tm.mobile/edits
         {
           "code" : 403,
           "errors" : [ {
             "domain" : "global",
             "message" : "The caller does not have permission",
             "reason" : "forbidden"
           } ],
           "message" : "The caller does not have permission",
           "status" : "PERMISSION_DENIED"
         }
    

    All the damn time. I tried creating multiple gcp projects, adding removing them, creating removing service account, givin them Owner role, or admin uiser permissions in Play console... I'm getting desperate

    If you could help, I'd be so glad

    // Maybe one more clue. In the new redesigned Play console, whever I click 'API Access', I get "Unexpected error bla bla. Try again". So I switched to the classic visuals, and there it appears to be working -- maybe a Google issue afterall?

    bug waiting-for-reply 
    opened by ursusursus 24
  • Customize 'Release name' in playstore

    Customize 'Release name' in playstore

    After uploading apk to play store there is possible to put own Release name, it is by default fill with versionCode.

    I was originally expected that

    outputProcessor { // this: ApkVariantOutput
        versionNameOverride = 'pokus'
    }
    

    will do this works, but it looks that it does nothing.

    Is there any way how to modify it by the plugin? Or there is a limitation on Google Play API side?

    Plugin version 2.0.0

    enhancement feature:bundle feature:apk 
    opened by tprochazka 24
  • Receive 403 error when trying to publish to other channel

    Receive 403 error when trying to publish to other channel

    Hi there,

    Thanks for the great plugin beforehand.

    We have been using the play publisher plugin and works great deploying to 'alpha' channel on Google Play Store. However we just discover when we try to change to publish certain version to 'beta' channel, we receive 403 error. The error is like below

    > com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
      {
        "code" : 403,
        "errors" : [ {
          "domain" : "androidpublisher",
          "message" : "Version ???? of this app can not be downloaded by any devices as 
    they will all receive APKs with higher version codes.",
          "reason" : "multiApkShadowedActiveApk"
        } ],
        "message" : "Version ???? of this app can not be downloaded by any devices 
    as they will all receive APKs with higher version codes."
      }
    

    Is there any workaround to publish from 'alpha' to 'beta' ?

    Thanks

    opened by otnateos 24
  • Add upload of universal apk back as a config option

    Add upload of universal apk back as a config option

    I'm building and uploading an universalApk with universalApk true as an fallback apk.
    UniversalApk upload was removed in #393, please add it back as an configurable option.

    enhancement feature:apk 
    opened by 1110101 22
  • --artifact-dir doesn't work as expected

    --artifact-dir doesn't work as expected

    I'm using the latest build, which I believe is 2.2.0 at the current time.

    I applied --artifact-dir to my build, but it didn't work, and it tried to start building my project. I didn't realize it at the time, but the directory I was pointing too was a relative path from the root project, not from the android module that I had the play-publisher plugin applied. It probably wasn't able to find it the directory, or the bundle I was trying to have it find, and instead of erring like I'd expect, instead it tried to build it.

    I wasn't able to see an error, and actually understand what was happening until I tried artifactDir.

    This behavior is unexpected. If I supply the --artifact-dir param, I'd expect it to behave the exact same as the artifactDir parameter.

    bug 
    opened by ScottPierce 21
  • error 403 when publish listing

    error 403 when publish listing

    Describe the bug

    publishListing results in

    com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden { "code" : 403, "errors" : [ { "domain" : "androidpublisher", "message" : "Invalid screenshot dimensions.", "reason" : "invalidScreenshotDimensions" } ], "message" : "Invalid screenshot dimensions." }

    To Reproduce

    Steps to reproduce the behavior (what tasks are you running, what's your play config, etc.)

    Versions

    latest released version

    Expected behavior

    Expected all files to upload. Issue seems to be related to 7in tablet graphics, of which I have 2. I uploaded BOTH via website without any problems. So it is strange that the API rejects it? Are there any other limits in place maybe?

    Image size is 2809x1410 and 1440x2773

    Additional context

    bug blocked-by-api feature:listing 
    opened by githubber2222 21
  • Ability to upload AAB release build file

    Ability to upload AAB release build file

    This command ./gradlew :app:publishReleaseBundle builds aab and release it to internal track. But what if we wanted to reuse the generated aab file for other purposes? Can we instead build aab file with gradle and provide it to GPP in the command to save build minute for CI CD? Thanks

    docs 
    opened by ArcherEmiya05 20
  • Vulnerability

    Vulnerability

    Describe the bug

    A clear and concise description of what the bug is.

    Introduced through : com.github.triplet.gradle:[email protected] Fixed in: com.google.oauth-client:[email protected]

    Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature via the IdTokenVerifier method, due to missing signature verification of the ID Token. Exploiting this vulnerability makes it possible for the attacker to provide a compromised token with a custom payload.

    How To Reproduce

    Versions

    play[email protected]

    • Gradle Play Publisher:
    • Gradle Wrapper:
    • Android Gradle Plugin:

    Tasks executed

    What tasks did you run? For example, publishBundle.

    publishReleaseBundle

    Expected behavior

    A clear and concise description of what you expected to happen.

    Additional context (if a crash, provide stack trace)

    Add any other context about the problem here. If this bug is a crash, run the task with --stacktrace to get the full context.

    bug dontclose 
    opened by NolanDon 2
  • Preserving updatePriority

    Preserving updatePriority

    Problem description

    updatePriority works fine when uploading a bundle. But when promoting the bundle manually it is gone. Also when using ./gradlew promoteArtifact the updatePriority prop seems to be gone. Is there any way to promote a bundle and keep the updatePriority or maybe add it again during promotion?

    Potential solutions/workarounds

    Introducing a possibility to keep updatePriority intact.

    enhancement feature:bundle feature:apk 
    opened by D4nt4lion 0
  • Firebase Crashlytics mapping file isn't uploaded while publishing artifacts

    Firebase Crashlytics mapping file isn't uploaded while publishing artifacts

    Describe the bug

    uploadCrashlyticsMappingFile$variantName is not there at the time of configuring of publish* tasks and is not wired as dependency for these tasks resulting in lack of mapping file in crashlytics for the published release

    How To Reproduce

    Apply com.google.firebase.crashlytics plugin to any Gradle module with com.android.application and com.github.triplet.play, run publishBundle

    Versions

    • Gradle Play Publisher: 3.7.0
    • Gradle Wrapper: 7.5.0
    • Android Gradle Plugin: 7.2.1
    • Firebase Crashlytics Gradle Plugin: 2.9.1

    Tasks executed

    publishAnyVariantBundle

    Expected behavior

    uploadCrashlyticsMappingFile$variantName is executed whenever publish task for specified variantName is executed

    bug feature:bundle feature:apk 
    opened by sergei-lapin 8
  • Retaining causes gradle configuration to break

    Retaining causes gradle configuration to break

    Describe the bug

    It looks like adding the retain node to the play or playConfig nodes causes gradle to fail configuration

    How To Reproduce

    Add the following to a new project in Android

        play {
            retain {
                artifacts.set(listOf(123))
            }
        }
    

    Versions

    • Gradle Play Publisher: 3.7.0
    • Gradle Wrapper: 7.4
    • Android Gradle Plugin: 7.3.0-beta1

    Tasks executed

    Any tasks just ./gradlew tasks will cause it

    Expected behavior

    Retained values to be configured

    Additional context (if a crash, provide stack trace)

    It seems like I can get around it with

            retain.artifacts.add(123L)
    

    but I haven't tried to publish yet.

    Stacktrace:

    * Where:
    Build file '/Users/bparent/dev/fun/PublisherRetainIssue/app/build.gradle' line: 7
    
    * What went wrong:
    A problem occurred evaluating project ':app'.
    > No signature of method: build_9ej6tobvvvxxnfx9lh6wawuq1.android() is applicable for argument types: (build_9ej6tobvvvxxnfx9lh6wawuq1$_run_closure1) values: [[email protected]]
    
    * Try:
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.
    
    * Exception is:
    org.gradle.api.GradleScriptException: A problem occurred evaluating project ':app'.
            at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:93)
            at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.lambda$apply$0(DefaultScriptPluginFactory.java:133)
            at org.gradle.configuration.ProjectScriptTarget.addConfiguration(ProjectScriptTarget.java:79)
            at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:136)
            at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
            at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62)
            at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
            at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:360)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:378)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:359)
            at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42)
            at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
            at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35)
            at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:109)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:360)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$withProjectLock$2(DefaultProjectStateRegistry.java:408)
            at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:408)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:389)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:359)
            at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:100)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
            at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:72)
            at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:760)
            at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:151)
            at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.ensureConfigured(DefaultProjectStateRegistry.java:328)
            at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:33)
            at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:49)
            at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:50)
            at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64)
            at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
            at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
            at org.gradle.initialization.VintageBuildModelController.lambda$prepareProjects$3(VintageBuildModelController.java:89)
            at org.gradle.internal.model.StateTransitionController.lambda$doTransition$12(StateTransitionController.java:227)
            at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
            at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:226)
            at org.gradle.internal.model.StateTransitionController.lambda$transitionIfNotPreviously$10(StateTransitionController.java:201)
            at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
            at org.gradle.internal.model.StateTransitionController.transitionIfNotPreviously(StateTransitionController.java:197)
            at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:89)
            at org.gradle.initialization.VintageBuildModelController.prepareToScheduleTasks(VintageBuildModelController.java:71)
            at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$prepareToScheduleTasks$2(DefaultBuildLifecycleController.java:134)
            at org.gradle.internal.model.StateTransitionController.lambda$doTransition$12(StateTransitionController.java:227)
            at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
            at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:226)
            at org.gradle.internal.model.StateTransitionController.lambda$maybeTransition$9(StateTransitionController.java:187)
            at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
            at org.gradle.internal.model.StateTransitionController.maybeTransition(StateTransitionController.java:183)
            at org.gradle.internal.build.DefaultBuildLifecycleController.prepareToScheduleTasks(DefaultBuildLifecycleController.java:132)
            at org.gradle.internal.buildtree.DefaultBuildTreeWorkPreparer.scheduleRequestedTasks(DefaultBuildTreeWorkPreparer.java:33)
            at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$doScheduleAndRunTasks$2(DefaultBuildTreeLifecycleController.java:89)
            at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:75)
            at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.doScheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:88)
            at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$4(DefaultBuildTreeLifecycleController.java:106)
            at org.gradle.internal.model.StateTransitionController.lambda$transition$6(StateTransitionController.java:166)
            at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
            at org.gradle.internal.model.StateTransitionController.lambda$transition$7(StateTransitionController.java:166)
            at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
            at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:166)
            at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:103)
            at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:69)
            at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31)
            at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
            at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:49)
            at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:69)
            at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:119)
            at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
            at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
            at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:128)
            at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
            at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
            at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:65)
            at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
            at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:65)
            at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
            at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
            at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
            at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
            at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
            at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:119)
            at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
            at org.gradle.tooling.internal.provider.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:103)
            at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
            at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
            at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:100)
            at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:88)
            at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
            at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62)
            at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41)
            at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
            at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
            at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:58)
            at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
            at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
            at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
            at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
            at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
            at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
            at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
            at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
            at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
            at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
            at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
            at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
            at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
            at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
            at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    Caused by: groovy.lang.MissingMethodException: No signature of method: build_9ej6tobvvvxxnfx9lh6wawuq1.android() is applicable for argument types: (build_9ej6tobvvvxxnfx9lh6wawuq1$_run_closure1) values: [[email protected]]
            at build_9ej6tobvvvxxnfx9lh6wawuq1.run(/Users/bparent/dev/fun/PublisherRetainIssue/app/build.gradle:7)
            at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:91)
            ... 152 more
    
    bug help wanted feature:other 
    opened by bparent 1
  • Properly export enums in public API

    Properly export enums in public API

    Ideally we can just use a type alias, but I don't think groovy will understand that. If the type alias doesn't work, we can pull resolution strategy and release status into their own module under the existing package name and export that.

    bug feature:other 
    opened by SUPERCILEX 4
  • Allow use of JWT access tokens instead of service account keys

    Allow use of JWT access tokens instead of service account keys

    Problem description

    This library requires a service account key to use. It should alternatively support JWT access tokens directly (what you exchange the service account key for with GCP). These can be issued by secret managers like Vault, and you aren't limited to 10 per service account.

    Potential solutions/workarounds

    Provide an environment variable for access tokens.

    Additional context

    enhancement feature:other 
    opened by thequailman 0
Releases(3.7.0-agp4.2)
  • 3.7.0-agp4.2(Nov 28, 2021)

    This release is identical-ish to v3.7.0, except that it includes the necessary changes to be compatible with the Android Gradle Plugin v4.2.x. There are no known bugs.

    It also includes a fix for Gradle 6.9: #1023.

    Source code(tar.gz)
    Source code(zip)
  • 3.7.0(Nov 28, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v7.x.

    Bug fixes

    • ResolutionStrategy.IGNORE checks have been updated to work with new API responses
    • Bootstrapped images now use the correct file extension (png vs jpg)

    Improvements

    • Credential parsing error messages have been improved
    • More progress has been made towards support the configuration cache (see #854 for progress)
    Source code(tar.gz)
    Source code(zip)
  • 3.6.0-agp4.2(Aug 7, 2021)

  • 3.6.0(Aug 2, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v7.x.

    Bug fixes

    • Underlying commit errors are no longer hidden by a sendChangesForReview error
    • A previously in progress release can now be promoted to completed successfully

    Improvements

    • Gradle 7.1 is properly supported now
    • When a user fraction is set with an unspecified release status, in progress is picked automatically
    Source code(tar.gz)
    Source code(zip)
  • 3.5.0(Jun 23, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v4.2.x. See GPP v3.5.0-agp7.0 for a release compatible with the Android Gradle Plugin v7.0.x.

    Bug fixes

    • The wrong credentials were being used when specified through playConfigs. This is now fixed.
    • A Google API change caused publishing to fail if the app was under review. This is now fixed.

    Improvements

    • For those with flavor dimensions, any lifecycle task you could want is now available, named following the Android Gradle Plugin conventions. Run ./gradlew tasks --group publishing to view available tasks.
    • On that same note, lifecycle tasks are now available for private uploads.
    • ⚠️ The bootstrap task was renamed to bootstrapListing while publish$variant was renamed to publish${variant}Apps.
    Source code(tar.gz)
    Source code(zip)
  • 3.5.0-agp7.0(Jun 23, 2021)

  • 3.4.0-agp7.0(Apr 11, 2021)

  • 3.4.0(Apr 11, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v4.1.x. See GPP v3.4.0-agp4.2 or v3.4.0-agp7.0 for a release compatible with the Android Gradle Plugin v4.2.x or v7.0.x respectively.

    Improvements

    • Credentials are now validated lazily. This means you don't have to specify credentials unless you are using a publishing task.
    • ⚠️ The internal sharing output file name has changed to support split APKs. Instead of being [timestamp].json, the name is now [apk-file-name].json.
    Source code(tar.gz)
    Source code(zip)
  • 3.4.0-agp4.2(Apr 11, 2021)

  • 3.3.0(Feb 23, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v4.1.x. See GPP v3.3.0-agp4.2 for a release compatible with the Android Gradle Plugin v4.2.x.

    New features

    • Support for single package multi-bundle uploads is now available. This enables using custom artifact directories with seperate phone and wear app bundles.

    Bug fixes

    • ResolutionStrategy.IGNORE stopped worked due to external API changes. This is now fixed.

    Behavior changes ⚠️

    • The global publish task has been replaced with an identical publishApps task. This resolves conflicts with the maven-publish plugin that had no other solution.
    Source code(tar.gz)
    Source code(zip)
  • 3.3.0-agp4.2(Feb 23, 2021)

  • 3.2.0(Jan 9, 2021)

    Note: This release is only compatible with the Android Gradle Plugin v4.1.x. See GPP v3.2.0-agp4.2 for a release compatible with the Android Gradle Plugin v4.2.x.

    New features

    • Flavor dimensions are now a supported configuration level in playConfigs. They override build types, but get overridden by product flavors.

    Bug fixes

    • Supported third-party plugins (like crashlytics) will no longer be invoked when using a pre-built custom artifact.
    Source code(tar.gz)
    Source code(zip)
  • 3.2.0-agp4.2-2(Jan 9, 2021)

  • 3.2.0-agp4.2(Jan 9, 2021)

  • 3.1.0-agp4.2-2(Jan 7, 2021)

  • 3.1.0(Dec 31, 2020)

    Note: This release is only compatible with the Android Gradle Plugin v4.1.x. See GPP v3.1.0-agp4.2 for a release compatible with the Android Gradle Plugin v4.2.x.

    New features

    • Native deobfuscation symbols are now uploaded alongside APKs.
    • Pending API changes are now validated when skipping a commit, enabling dry run use cases with --no-commit.
    • When using a custom artifact directory, mapping files can now be targeted to specific APKs. See the docs for more details.

    Bug fixes

    • Fixed a crash reading version codes with auto resolution on after a manual version bump was performed.
    • Added integration with crash reporting plugins (Crashlytics and Bugsnag currently) to automatically run their upload tasks on publish.
    • Mapping files are no longer uploaded when publishing an app bundle as the mapping file is already a part of the bundle.
    • The time between an API edit being generated and committed is now shorter, minimizing the chance of getting an editDeleted error.
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0-agp4.2(Dec 31, 2020)

    This release is identical to v3.1.0, except that it includes the necessary changes to be compatible with the Android Gradle Plugin v4.2.x.

    Known bugs (won't be fixed)

    • Intercepting the updated version code when using auto resolution is broken.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Sep 9, 2020)

    Note: Gradle 6.5 and the Android Gradle Plugin v4.1.0 are the new minimum requirements. GPP 2.x will not support AGP 4.1 or above.

    New features

    • Better compatibility with the maven-publish plugin. If present, GPP will now add its dependencies to the publish task.
    • Proxy authentication courtesy of @wintermute766.

    Bug fixes

    • Fixed a critical issue where playConfigs would sometimes inadvertently overwrite each other.

    Breaking changes

    • All properties now use the Gradle Property API. Upgrade steps: change foo = blah to foo.set(blah). For more guidance, see the updated docs.
    • The outputProcessor property has been removed. The same functionality can now be achieved using native AGP APIs.
    • Support for PKCS12 credentials (aka .p12 files) has been removed along with the serviceAccountEmail property. Use JSON credentials instead.
    • Deprecated task names have been removed.
    • promo-graphics are no longer supported in the Publishing API and have been removed.

    Behavior changes

    Promote task

    The promote task now handles its different configuration options more simply. Promotion needs a from track and a promote track. If the fromTrack isn't specified explicitly, the least stable release track will be used. If the promoteTrack isn't specified explicitly, it will be assumed that you want to do an in-place update so the resolved fromTrack will be used. Previously, the track property was involved in the computation of both other properties.

    Source code(tar.gz)
    Source code(zip)
  • 2.8.0(Jun 9, 2020)

    • Support for authenticating GPP with an environment variable! See the docs.
    • Support for in-app update priority.
    • Fixed an incompatibility with Gradle 6.5.
    • Fixed a crash publishing releases to a new track.
    • Removed unnecessary warnings.

    PS: this release uses a new publishing mechanism, so in theory you can use any of our modules directly (though this isn't officially supported).

    Source code(tar.gz)
    Source code(zip)
  • 2.7.5(Apr 5, 2020)

    • Fixed a compatibility issue with Gradle 6.3.
    • Fixed a bug causing local release notes to be picked from the promoteTrack instead of the fromTrack.
    Source code(tar.gz)
    Source code(zip)
  • 2.7.4(Apr 5, 2020)

  • 2.7.3(Mar 25, 2020)

    This release fixes a few key bugs:

    • Bootstrapping images started failing across various GPP versions due to an API change.
    • Using a product flavor named play would fail.
    • GPP would crash on a non-existent mapping file.

    In addition, partial compatibility with AGP 4.1.x is now available.

    Source code(tar.gz)
    Source code(zip)
  • 2.7.2(Feb 26, 2020)

    This release makes incompatibility errors with the Android Gradle Plugin clearer.

    Note: the minimum AGP version was bumped from 3.6.0-rc03 to 3.6.0 now that 3.6 stable has shipped.

    Source code(tar.gz)
    Source code(zip)
  • 2.7.1(Feb 22, 2020)

  • 2.7.0(Feb 22, 2020)

    This release is focused on fixing long-standing bugs and minor feature requests.

    Note: GPP v2.7 requires at least Gradle 6.2 and the Android Gradle Plugin 3.6.0.

    Improvements

    • Support for top-level graphics is now available. This means that you can put your app's icon (for example) in graphics/icon.png instead of graphics/icon/1.png.
    • If no local release notes are found, existing release notes from the Play Console will be carried over when publishing your APK or App Bundle.
    • You can now upload and/or install debuggable internal sharing artifacts.
    • A warning is now logged if your playConfigs contain an unrecognized variant, product flavor, or build type.

    Bug fixes

    • CLI params now always override your build script configuration instead of failing if you had playConfigs.
    • CLI params on lifecycle tasks (such as promoteArtifact instead of promoteReleaseArtifact) now propage down to their respective implementation tasks correctly.
    • The --artifact-dir CLI param is now correctly respected in eagerly configured Gradle projects.

    Deprecations

    • The --track CLI param on promotion tasks has been removed as it led to confusing bugs and unpredictable behavior. Use --promote-track instead.
    Source code(tar.gz)
    Source code(zip)
  • 2.6.2(Dec 28, 2019)

  • 2.6.1(Nov 20, 2019)

  • 2.6.0(Nov 16, 2019)

    This release of GPP requires at least Gradle 6.0.

    Bug Fixes

    • Fixed an incompatibility with Gradle 6.0
    • Fixed numerous bugs related to incremental play resource generation and listing publication
    • Clarified some ambitious logs and warnings
    Source code(tar.gz)
    Source code(zip)
  • 2.5.0(Nov 2, 2019)

    This release mainly consists of a huge refactor towards a testable architecture. As a bonus, numerous bugs have been fixed in the process.

    Other notable changes are:

    • Support for installing Internal Sharing artifacts. See the docs here.
    • PKCS12 based authentication is deprecated and will be removed in v3.
    Source code(tar.gz)
    Source code(zip)
  • 2.4.2(Sep 27, 2019)

    • Fix another AGP 3.6 incompatibility - #696, #711
    • Fix regression causing build failure on unproguarded builds - #711
    • Fix not all hidden files being ignored - #703
    Source code(tar.gz)
    Source code(zip)
Owner
null
gradle-android-scala-plugin adds scala language support to official gradle android plugin

gradle-android-scala-plugin gradle-android-scala-plugin adds scala language support to official gradle android plugin. See also sample projects at htt

saturday06 347 Aug 16, 2022
Ownership-gradle-plugin - Gradle code ownership verification plugin

Gradle code ownership verification plugin A gradle plugin that will verify owner

null 3 Mar 17, 2022
📦 Easily create github release

_ _ _ _ _ _ | | | (_) | | | | | __ _ _ __ __ _ __| | | ___ _____

사부작사부작 3 Apr 20, 2022
A Gradle plugin to support the Groovy language for building Android apps

Groovy language support for Android Deprecated: This plugin has been deprecated in favor of Kotlin which has the full support of JetBrains and Google.

Groovy programming language 856 Sep 7, 2022
Helper to upload Gradle Android Artifacts, Gradle Java Artifacts and Gradle Kotlin Artifacts to Maven repositories (JCenter, Maven Central, Corporate staging/snapshot servers and local Maven repositories).

GradleMavenPush Helper to upload Gradle Android Artifacts, Gradle Java Artifacts and Gradle Kotlin Artifacts to Maven repositories (JCenter, Maven Cen

 Vorlonsoft LLC 20 Aug 9, 2022
An Android Studio / IntelliJ plug-in help you upload your apk or listing to Google Play.

DroidLane An Android Studio / IntelliJ plug-in help you upload your apk or listing to Google Play. Installation Open Android Studio or IntelliJ IDEA O

Jintin 24 Jul 26, 2021
A Gradle plugin for providing your secrets to your Android project.

Secrets Gradle Plugin for Android A Gradle plugin for providing your secrets securely to your Android project. This Gradle plugin reads secrets from a

Google 515 Sep 28, 2022
Add a different ribbon to each of your Android app variants using this gradle plugin. Of course, configure it as you will

Easylauncher gradle plugin for Android Modify the launcher icon of each of your app-variants using simple gradle rules. Add ribbons of any color, over

Mikel 960 Sep 22, 2022
A powerful Gradle Plugin to help you demonstrate your android app

English | 简体中文 sample-gradle-plugin ?? A powerful Gradle Plugin to help you demonstrate your android app. We often write demo applications that contai

Yoo Zhou 8 Sep 7, 2022
Gradle plugin which downloads and manages your Android SDK.

DEPRECATED This plugin is deprecated and is no longer being developed. Tools and dependencies are automatically downloaded using version 2.2.0 of the

Jake Wharton 1.4k Sep 14, 2022
Gradle plugin which validates the licenses of your dependency graph match what you expect

Licensee ?? ?? A Gradle plugin which validates the licenses of your dependency graph match what you expect, or it fails your build! Jump to: Introduct

Cash App 469 Sep 29, 2022
Gradle plugin which helps you analyze the size of your Android apps.

Ruler Ruler is a Gradle plugin which helps you analyze the size of your Android apps. Motivation App size is an important metric which directly correl

Spotify 890 Oct 1, 2022
A Leiningen plugin for building Clojure/Android projects

lein-droid A Leiningen plugin to simplify Clojure development for Android platform. It acts as a build-tool for Clojure/Android projects. Usage First

Clojure/Android 644 Sep 26, 2022
IntelliJ platform plugin that shows errors, warnings, and other inspection highlights inline.

IntelliJ plugin that shows errors, warnings, and other inspection highlights inline. Simply install the plugin and inspection descriptions will appear

null 5 Sep 24, 2022
K6-intellij-plugin - IntelliJ-based Plugin to run k6 tests locally or in the k6 Cloud from your IntelliJ IDE

IntelliJ-based Plugin to run k6 tests locally or in the k6 Cloud from your Intel

Mikhail Bolotov 4 Aug 15, 2022
CKlib is a gradle plugin that will build and package C/C++/Objective-C code for Kotlin/Native.

C Klib CKlib is a gradle plugin that will build and package C/C++/Objective-C code for Kotlin/Native. The Problem When you want to access C-etc code f

Touchlab 70 Jul 14, 2022
A gradle plugin to optimize built jars through individual file optimizations and increased compression

Machete Machete is a gradle plugin that attempts to optimize the size of output JARs through both individual file optimizations and overall compressio

Silver 8 Jul 5, 2022
A Gradle Plugin that removes unused resources in Android projects.

#Lint Cleaner Plugin Removes unused resources reported by Android lint including strings, colors and dimensions. Depracated As of Android Studio 2.0+

Marco RS 707 Aug 8, 2022