Triple-T / gradle-play-publisher

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.
MIT License
4.1k stars 340 forks source link

Variant specific application id not respected while publishing #979

Open shanselm-ergon opened 3 years ago

shanselm-ergon commented 3 years ago

I work in a project, which uses multi-dimension-flavor android builds. Each flavor gets a distinct application id (not just a suffix, the id changes completely). This setup worked well until I updated to AGP 4.2.2 and GPP 3.5.0 (works with AGP 4.1.3 and GPP 3.4.0).

The abstract setup looks like this:

android {
    ...
    flavorDimensions("env", "dim")

    productFlavors {
        create("a") {
            dimension = "env"
        }
        create("b") {
            dimension = "env"
        }
        create("x") {
            dimension = "dim"
        }
        create("y") {
            dimension = "dim"
        }
    }
    ...
}
androidComponents.onVariants { variant ->
    variant.applicationId.set(
        when (variant.flavorName) {
            "aX" -> "a.x"
            "bX" -> "b.x"
            "aY" -> "a.y"
            "bY" -> "b.y"
            else -> throw(IllegalStateException("What's your flavor? $flavorName!"))
        }
    )
}

With the old AGP version, the syntax was slightly different, but I guess it was adopted correctly:

android {
    ...
    onVariantProperties {
        applicationId.set(
            when (flavorName) {
                "aX" -> "a.x"
                "bX" -> "b.x"
                "aY" -> "a.y"
                "bY" -> "b.y"
                else -> throw(IllegalStateException("What's your flavor? $flavorName!"))
            }
        )
    }
    ...
}

When I now try to upload one of my apps to the play store with ./gradlew publishAXReleaseApps I get the following error back:

-------------- REQUEST  --------------
POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/x.y.z/edits
Accept-Encoding: gzip
Authorization: <Not Logged>
User-Agent: gradle-play-publisher Google-API-Java-Client/1.31.5 Google-HTTP-Java-Client/1.39.2 (gzip)
x-goog-api-client: gl-java/11.0.11 gdcl/1.31.5 linux/4.15.0
Content-Encoding: gzip

curl -v --compressed -X POST -H 'Accept-Encoding: gzip' -H 'Authorization: <Not Logged>' -H 'User-Agent: gradle-play-publisher Google-API-Java-Client/1.31.5 Google-HTTP-Java-Client/1.39.2 (gzip)' -H 'x-goog-api-client: gl-java/11.0.11 gdcl/1.31.5 linux/4.15.0' -H 'Content-Encoding: gzip' -d '@-' -- 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/x.y.z/edits' << $$$
-------------- RESPONSE --------------
HTTP/1.1 404 Not Found
Transfer-Encoding: chunked
X-Frame-Options: SAMEORIGIN
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private
Server: ESF
X-Content-Type-Options: nosniff
Content-Encoding: gzip
Vary: Referer
Vary: X-Origin
Vary: Origin
X-XSS-Protection: 0
Date: Mon, 12 Jul 2021 08:50:19 GMT
Content-Type: application/json; charset=UTF-8

Total: 308 bytes
{
  "error": {
    "code": 404,
    "message": "Package not found: x.y.z.",
    "errors": [
      {
        "message": "Package not found: x.y.z.",
        "domain": "global",
        "reason": "notFound"
      }
    ],
    "status": "NOT_FOUND"
  }
}

:app:publishAXReleaseApk (Thread[Execution worker for ':',5,main]) completed. Took 0.637 secs.

And here we see the problem, the package it is looking for is not the variants application id, but the default application id defined in the manifest file, which matches the package structure.

It seems like the variants application id adjustments are not propagated to the publish task.

To be honest, I'm not sure if it is a problem in the AGP, or in the GPP, or even in my configuration, but I couldn't figure it out. Any help would be appreciated.

How To Reproduce

See description above.

Versions

Tasks executed

./gradlew publishAXReleaseApps.

Expected behavior

The app gets uploaded to the play store.

Additional context (if a crash, provide stack trace)

See description above.

SUPERCILEX commented 3 years ago

Yeah, this one is a duplicate of #948. Looks like it is going to be an issue, so I'll have to give the approach I wrote in the last comment a try.

In the meantime, do id "com.github.triplet.play" version "..." apply false and then at the bottom of your build script put apply(plugin = "com.github.triplet.play"). The problem is that the plugin currently needs correct app IDs at configuration time.

shanselm-ergon commented 3 years ago

Thanks for your fast reply. The described approach unfortunately won't work for me, because I use the play configuration section, which won't be available if the plugin is not applied. Is there an other way of configuring the plugin?

play {
    serviceAccountCredentials.set(file(extra.get("googlePlayPublishKeyFile")!!))
    track.set("internal") // internal (default) / alpha / beta / production or any custom track
}
SUPERCILEX commented 3 years ago

Right, you'll need to use this syntax:

import com.github.triplet.gradle.play.PlayPublisherExtension

// ...

configure<PlayPublisherExtension> {
  // ...
}
micer commented 3 years ago

I have the same issue with incorrect application id. @SUPERCILEX how to use configure<PlayPublisherExtension> in Groovy build.gradle?

SUPERCILEX commented 3 years ago

With groovy, you should be able to still use the play block. It's all dynamic so as long as the apply plugin: ... comes before you'll be good.

micer commented 3 years ago

Unfortunately GPP is still using wrong application id for me. I'm setting it by applicationVariants.all { variant -> setApplicationId(variant)

I'm using id("com.github.triplet.play") version "3.4.0-agp4.2" apply false in global build.gradle and apply plugin: "com.github.triplet.play" in :app build.gradle because of dependencies conflict (https://github.com/Triple-T/gradle-play-publisher/issues/901#issuecomment-758311851).

I have play block after apply plugin: .... Any idea? I suppose it's not possible to set application id to GPP later than at configuration time?

SUPERCILEX commented 3 years ago

And you're applying the plugin after touching the application variants?

micer commented 3 years ago

Yes, I tried this order:

android {
    applicationVariants.all { variant ->
        setApplicationId(variant)
        println("setApplicationId")
    }
}

apply plugin: 'com.github.triplet.play'

android {
    playConfigs {
        println("GPP playConfigs")
        abcRelease {
            enabled.set(true)
        }
        ...
    }
}

play {
    println("GPP play")
    enabled.set(false)
    serviceAccountCredentials.set(file("config.json"))
    track.set("production")
    releaseStatus.set(com.github.triplet.gradle.androidpublisher.ReleaseStatus.DRAFT)
}

I tried to put apply plugin: 'com.github.triplet.play' in android {} block between touching the application variants and playConfig, but it's the same.

From logs I can see the order:

GPP playConfigs
GPP play
setApplicationId
setApplicationId
setApplicationId
...
SUPERCILEX commented 3 years ago

Ah shoot, that's nasty. I think you'll have to use the new API:

androidComponents {
    onVariants { variant ->
        variant.applicationId.set("blah")
    }
}

apply plugin: 'com.github.triplet.play'

// ...

What Android Gradle Plugin version are you using? It might look like this instead:

androidComponents {
  onVariantProperties {
    applicationId.set("blah")
  }
}
yital9 commented 2 years ago

Hi @SUPERCILEX. Do you have any plans to fix this issue? We are also currently facing this problem and none of workarounds have worked out.

SUPERCILEX commented 2 years ago

I'd like to, but I haven't come up with a good solution yet. The problem is that we want full parallelism across app IDs while supporting synchronous access to the same app ID across projects, but we can't truly know the app ID until after task creation which means we can't group the tasks into app ID buckets.

In terms of workarounds, this means you need to finalize the app ID before GPP reads it. I'm not sure what your specific case looks like, but if you can fully specify your different app IDs in the productFlavors, that should fix things.

In terms of proper solutions, I did come up with one idea that would maintain our desired functionality. The main problems is that it vastly increases complexity. The gist is this:

I basically need to think about how to guarantee correctness of that last step, but haven't prioritized it.

Legion2 commented 2 years ago

Our use case is, that we need to migrate to another app id, but we want to publish to both (new and old) app id during the migration period. Is this currently possible?

yital9 commented 2 years ago

Yes, we specify the applicationId not only in productFlavors, but also customize them in the following way

android {
   ...
   applicationVariants.all {
       if (name.contains("foo", true)) {
           (mergedFlavor as MergedFlavor).applicationId = "$applicationId.foo"
       }
   }
}

It'd be impossible for us to use only productFlavors, because historically we have such customized app ids, that could not be achieved only with productFlavors.

I thought a bit about a crashlytics plugin, that works fine in this situation. GMS has a static google-services.json file, where the package_name is also defined. So they can match somehow this information between firebase project and local flavor with our customized applicationId.

tadfisher commented 2 years ago

Have you tried beforeVariants instead of onVariants?

yital9 commented 2 years ago

A variant from beforeVariants hasn't an applicationId property.