After Gradle 8.x
Error: "Build Type contains custom BuildConfig fields, but the feature is disabled"
Need to enable buildConfig
for variant.buildConfigFields.set()
, it's default value was true
but now is false
:
android {
buildFeatures {
buildConfig = true
}
}
Error: "Could not create an instance of type com.android.build.api.variant.impl.LibraryVariantBuilderImpl ...
Namespace not specified. Specify a namespace in the module's build
file"
namespace
is required in module level build scripts now. You need to specify it for each module separately, and it should be same as package name of that module (not appId).
This is also related to generated R
class, it will become my.module.package.R
. Another breaking change is you can't use this.module.package.R
for referring resources (drawable, string...) of another module you depend on, you have to use my.another.module.R.drawable.login
. Because previously default value of android.nonTransitiveRClass
flag was false
and R
included drawables of every module you depend on. Now its default value is true
, so R
only contains resources of that module (improves build time).
Additionally you need to remove package=""
from AndroidManifest.xml of each module.
After Gradle 7.x
Instead of applicationVariants.all{}
, we now use androidComponents { onVariants{ .. }}
outside android{}
block. This code should work on Gradle 7.0.2 and AGP 7.0.1:
androidComponents {
onVariants { variant ->
variant.buildConfigFields.put("MY_CUSTOM_FIELD", BuildConfigField("String", "MyCustomValue", null))
variant.manifestPlaceholders.put("MY_MANIFEST_FIELD", "MyManifestValue")
}
}
On AGP 7.0.x, there is no way to set signingConfig
for mergedFlavor
(buildType+flavor). You can set for buildType or flavor individually, but not for combination.
On AGP 7.1.x, you can do it. But it requires AGP 7.1.0-alpha10, Gradle 7.2-rc-3, AndroidStudio BumbleBee 2021.1.1 alpha10:
androidComponents {
onVariants { variant ->
variant.signingConfig?.setConfig(android.signingConfigs.getByName("buildTypeXFlavorA"))
}
}
Before Gradle 7.x
To make changes on different variants (buildType+productFlavor), i had to use android.applicationVariants.all{}
. But different paths used to achieve multiple signingConfig
, manifestPlaceholders
, buildConfigField
1) manifestPlaceholders
applicationVariants.all{
val variant = this
}
There is no getter/setter for manifestPlaceholders
on variant
object. Following this, we can make variant.mergedFlavor
mutable. Setting manifestPlaceholders
on variant.mergedFlavor
did work.
import com.android.builder.core.DefaultProductFlavor
applicationVariants.all{
val manifestPlaceholders: Map<String, String>
val variant = this
val mutableMergedFlavor = variant.mergedFlavor as DefaultProductFlavor
mutableMergedFlavor.addManifestPlaceholders(manifestPlaceholders)
}
2) buildConfigField
Using the same approach, calling addBuildConfigField(ClassFieldImpl(type, name, value))
on mutableMergedFlavor
did not work. But instead, it can be set directly on variant
.
import com.android.builder.internal.ClassFieldImpl
applicationVariants.all{
val buildConfigFields: List<ClassFieldImpl>
val variant = this
buildConfigFields.forEach {
variant.buildConfigField(it.type, it.name, it.value)
}
}
3) signingConfig
signingConfig
can be set on mutableMergedFlavor
shown above, except on debug
variants. All debug
variants use default signing options, even if you set it on variant.mergedFlavor
. But if you set default as null, then you can override it as well.
import com.android.builder.core.DefaultProductFlavor
signingConfigs {
create("myDebug") {}
}
buildTypes {
getByName("debug") {
signingConfig = null // to override
}
}
applicationVariants.all{
val variant = this
val mutableMergedFlavor = variant.mergedFlavor as DefaultProductFlavor
mutableMergedFlavor.signingConfig = signingConfigs.getByName("myDebug")
}
To put all together:
import com.android.build.gradle.api.ApplicationVariant
import com.android.builder.internal.ClassFieldImpl
import com.android.builder.model.SigningConfig
import com.android.builder.core.DefaultProductFlavor
import java.util.*
fun configureVariant(variant: ApplicationVariant,
signingConfig: SigningConfig,
buildConfigFields: List<ClassFieldImpl>,
manifestPlaceholders: Map<String, String>) {
println("configureVariant: ${variant.name}")
buildConfigFields.forEach {
variant.buildConfigField(it.type, it.name, it.value)
}
val mutableMergedFlavor = variant.mergedFlavor as DefaultProductFlavor
mutableMergedFlavor.signingConfig = signingConfig
mutableMergedFlavor.addManifestPlaceholders(manifestPlaceholders)
}
android {
signingConfigs {
create("myDebug") {}
create("myRelease") {}
}
flavorDimensions("region")
productFlavors {
create("global") {
setDimension("region")
setApplicationId("")
}
create("local") {
setDimension("region")
setApplicationId("")
}
}
buildTypes {
getByName("debug") {
signingConfig = null
}
}
applicationVariants.all {
val variant = this
when {
variant.name.equals("localDebug", true) -> {
configureVariant(
variant,
signingConfigs.getByName("localDebug"),
listOf(ClassFieldImpl("String", "NAME", "\"VALUE\"")),
mapOf("KEY" to "VALUE")
)
}
variant.name.equals("globalStaging", true) -> {
configureVariant(
variant,
signingConfigs.getByName("globalStaging"),
listOf(ClassFieldImpl("String", "NAME", "\"VALUE2\"")),
mapOf("KEY" to "VALUE2")
)
}
}
}
}