6

I am converting an Android app to the Gradle Kotlin-DSL by using Kotlinscript files.

I have a problem converting our applicationId logic. We don't use the defaultConfiguration with applicationId plus various applicationIdSuffix for our flavors but a custom logic. The logic is described in this SO answer, here is the groovy code:

flavorDimensions "price", "dataset"

productFlavors {
    free { dimension "price" }
    paid { dimension "price" }
    dataset1 { dimension "dataset" }
    dataset2 { dimension "dataset" }
}

android.applicationVariants.all { variant ->
    def mergedFlavor = variant.mergedFlavor
    switch (variant.flavorName) {
        case "freeDataset1":
            mergedFlavor.setApplicationId("com.beansys.freeappdataset1")
            break
        case "freeDataset2":
            mergedFlavor.setApplicationId("com.beansys.freedataset2")
            break
        case "paidDataset1":
            mergedFlavor.setApplicationId("com.beansys.dataset1paid")  
            break
        case "paidDataset2":
            mergedFlavor.setApplicationId("com.beansys.mypaiddataset2")
            break
    }
}

With kotlin I cannot alter the applicationId of the mergedFlavor like in groovy. It is a val and therefore can't be changed.

Any elegant solution to solve this?

Henning
  • 2,202
  • 1
  • 17
  • 38

3 Answers3

12

Google added the variants API with the Android Gradle Plugin 7.0.0. With it we can alter the applicationId.

android {
    flavorDimensions.addAll(listOf("price", "dataset"))

    productFlavors {
        create("free") { dimension = "price" }
        create("pro") { dimension = "price" }
        create("dataset1") { dimension = "dataset" }
        create("dataset2") { dimension = "dataset" }
    }
}

androidComponents {
    onVariants { variant ->
        val applicationId = when(variant.flavorName) {
            "freeDataset1" -> "com.beansys.freeappdataset1"
            "freeDataset2" -> "com.beansys.freedataset2"
            "proDataset1" -> "com.beansys.dataset1paid"
            "proDataset2" -> "com.beansys.mypaiddataset2"
            else -> throw(IllegalStateException("Whats your flavor? ${variant.flavorName}!"))
        }
        variant.applicationId.set(applicationId)
    }
}

Note that it is probably better to use a task to determine the applicationId.

For more informations see the following resources:

Henning
  • 2,202
  • 1
  • 17
  • 38
  • Can you add the same script for groovy? Would be very helpful for me. – S. Gissel Feb 11 '22 at 20:31
  • @S.Gissel I created this question for the Kotlin DSL after only finding a solution for Groovy some years ago. You can find that question and the according Groovy solution there: https://stackoverflow.com/a/68835727/2793394 – Henning Feb 15 '22 at 12:29
3

// Update: There is now a non-hacky way to do it. See my other answer.

// Original answer: The trick is to cast the mergedFlavor to MergedFlavor and than change the applicationId for it:

import com.android.build.gradle.internal.core.MergedFlavor

android {
    flavorDimensions("price", "dataset")

    productFlavors {
        create("free") { dimension = "price" }
        create("pro") { dimension = "price" }
        create("dataset1") { dimension = "dataset" }
        create("dataset2") { dimension = "dataset" }
    }

    android.applicationVariants.all {
        val applicationId = when(name) {
            "freeDataset1" -> "com.beansys.freeappdataset1"
            "freeDataset2" -> "com.beansys.freedataset2"
            "proDataset1" -> "com.beansys.dataset1paid"
            "proDataset2" -> "com.beansys.mypaiddataset2"
            else -> throw(IllegalStateException("Whats your flavor? $name!"))
        }
        (mergedFlavor as MergedFlavor).applicationId = applicationId
    }
}

Any cleaner solution is appreciated!

// History:

Originaly this answer contained a cast to DefaultProductFlavor which doesn't work since the Android Gradle Plugin 4.0.0 and a cast to AbstractProductFlavor which is now deprecated.

Henning
  • 2,202
  • 1
  • 17
  • 38
2

Adding to Henning's answer and comment by Mark regarding that AbstractProductFlavor is deprecated, you can instead cast as MergedFlavor:

(mergedFlavor as com.android.build.gradle.internal.core.MergedFlavor).applicationId = applicationId

Tested with Android Gradle Plugin 4.1.2 but I guess it is valid since 4.0.0

snielsen
  • 21
  • 4
  • Thank you for the hint! Beats my `@Suppress("DEPRECATION")` annotation :-D. I updated my answer – Henning Feb 08 '21 at 15:42
  • Thanks! Is the fact it's in an 'internal' package, potentially an issue further down the road? – Mark Feb 11 '21 at 04:10
  • Well, using the `getApplicationId` is showing a deprecation warning by now as well. So at some point this might not work anymore either. We lately ran into an issue that a 3rd party plugin did not pick up the correct application ID which we define by this approach. It seems like it depends on WHEN someone requests the final application ID... – snielsen Apr 30 '21 at 16:25