How to change version code after AGP 7.0.0-alpha15 - android

Before AGP 7.0.0-alpha15 I could change version code of an app for example like that
android {
defaultConfig {
applicationVariants.all {
if (buildType.name == "debug") {
outputs.forEach { output ->
(output as? com.android.build.gradle.internal.api.ApkVariantOutputImpl)?.versionCodeOverride = 1
}
}
}
}
}
applicationVariants seems missing after AGP 7.0.0-alpha15, how to change it?
PS: It seems ok in plain gradle, above is Kotlin
Edit
With answer from below I was able to override version code in build:
android {
androidComponents.onVariants { appVariant ->
if (appVariant.buildType == "release") {
appVariant.outputs.forEach {
it.versionCode.set(1)
}
}
}
}

The Variant API is going to change to a lazily-evaluated model in AGP 7.0.0, and it seems like Alpha 15 has removed the old APIs for this now. Going forward, you will need to use the androidComponents DSL, which gives access to variants. I am not sure if you'll be able to rewrite the version code like this, however. Check out beforeVariants and onVariants for more info:
android {
androidComponents.beforeVariants { variantBuilder ->
// Callback before variants are built. Can be modified, but doesn't allow access to outputs
}
androidComponents.onVariants { variant ->
// Callback after variants are built. Apparently it's read-only access at this point, but outputs are available here
println(variant.outputs)
}
}

In Java plugin code, one can set the version code & name alike this:
class SomePlugin implements Plugin<Project> {
#Override
#SuppressWarnings("UnstableApiUsage")
public void apply(#NotNull Project project) {
ApplicationAndroidComponentsExtension androidComponents = project.getExtensions()
.getByType(ApplicationAndroidComponentsExtension.class);
androidComponents.finalizeDsl(extension -> {
for (AndroidSourceSet sourceSet : extension.getSourceSets()) {
System.out.println(sourceSet.getName());
}
});
int versionCode = 1;
String versionName = "1.0.0";
VariantSelector selector = androidComponents.selector().all();
androidComponents.onVariants(selector, variant -> {
for (VariantOutput variantOutput : variant.getOutputs()) {
variantOutput.getVersionName().set( versionName );
variantOutput.getVersionCode().set( versionCode );
System.out.println(">>>> " +
variant.getName() + " " +
variantOutput.getVersionCode().get() + " / " +
variantOutput.getVersionName().get());
}
});
}
}
finalizeDsl happens before onVariants.

android {
// ..
splits {
abi {
enable true
reset()
include 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
}
}
// ..
}
androidComponents {
onVariants(selector().all()) { appVariant ->
for (VariantOutput variantOutput : appVariant.getOutputs()) {
def versionCodes = ['[armeabi]' : 100000,
'[armeabi-v7a]' : 200000,
'[x86]' : 300000,
'[arm64-v8a]' : 400000,
'[x86_64]' : 500000]
String abi = variantOutput.getFilters().identifier;
Integer version = versionCodes.get(abi) + versionCode
if (appVariant.getName().contains("Debug")) {
version += 10000
}
variantOutput.getVersionCode().set(version);
}
}
}
dependencies {
// ...
}

Related

What is alternative to `variant.resValue` with AGP 7.0.0+?

I am trying to migrate to Android Gradle Plugin 7.
I have the following code that needs migration:
applicationVariants.all { variant ->
// do some processing to obtain string apiKeyValue
variant.resValue "string", "api_key", apiKeyValue
}
I have looked at the migration blog post here android developers blog but still no clear reference to how to create dynamic
resValue
Any thoughts?
I also tried to use something similar to
androidComponents {
onVariants(selector().all(), { variant ->
// do some processing to obtain string apiKeyValue
addResValue("api_key", "string", apiKeyValue, "Value from variant")
})
}
But no luck as
addResValue
method is not found.
After a bit of searching and trial and error, the following code worked for me:
androidComponents {
onVariants(selector().all(), { variant ->
// do some processing to obtain string apiKeyValue
variant.resValues.put(variant.makeResValueKey("string", "api_key"), new ResValue(apiKeyValue, "Variant Name"))
})
}
The above code is a snippet from my build.gradle file. I took inspiration from here gradle-recipes
For groovy and AGP 7.2.1 old way still works. Only keys for resValues now have type prefix ie "string/app_name". instead of "app_name".
android{
applicationVariants.all{ variant ->
def strRes = variant.mergedFlavor.resValues.get("string/app_name")
if(strRes != null){
println( "string/app_name = " + strRes.getValue())
variant.resValue 'string', 'app_name', "${strRes}New"
}
}
}

Could not get unknown property 'apkNames' in android gradle plugin 4.1.0

I am using this code in build.gradle:
android {
applicationVariants.all { variant ->
variant.packageApplicationProvider.configure { packageApplicationTask ->
doLast {
packageApplicationTask.apkNames.each { apkName ->
def apkDir = "./build/outputs/apk/${flavorName}/${buildType.name}"
def apkDestName = apkName.replace("app-", "stickerly-android-" + variant.versionName + "-").replace(".apk", "-" + getDate() + ".apk")
println "#####Rename ${variant.name} Apk File"
copy {
from("$apkDir/$apkName").into(apkDir).rename { String fileName -> apkDestName }
}
println "#####Copy mapping File"
def mappingDir = "./build/outputs/mapping/${flavorName}${buildType.name.capitalize()}"
copy {
from("$mappingDir/mapping.txt").into(mappingDir).rename {
"mapping-stickerly-${variant.versionName}.txt"
}
}
}
}
}
}
}
With this code I rename apk file and copy mapping file. I worked in android gradle plugin 4.0, but it does not work in 4.1 with this message
Where:
Script '/Users/snow/workspace/stickerly-android/app/build-android-extra.gradle' line: 5
What went wrong:
Execution failed for task ':app:packageExternalArm8Debug'.
Could not get unknown property 'apkNames' for task ':app:packageExternalArm8Debug' of type com.android.build.gradle.tasks.PackageApplication.
I think API has changed but I can not find any documents. Someone can help me?
Thanks.
property apkNames is removed in AGP 4.1
you can try this
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (!state.failure
&& task.project.name == project.name
&& task.name.startsWith("package")
&& !task.name.endsWith("UnitTest")) {
def outputDir = task.outputDirectory.getAsFile().get()
task.variantOutputs.getOrNull()?.each { variant ->
println "" + outputDir + "/" + variant.outputFileName.get()
}
}
}
add this at the end of your build.gradle file.
change println to whatever logic you want.
by the way, if you want to check the properties you may use, just add gradle plugin as a dependency of your project, click Sync in Android Stuido, then you can find it in External Librarys (key map: Command + 1, and switch to project view).
like this
dependencies {
implementation 'com.android.tools.build:gradle:4.1.0'
}
and these properties and tasks are intentionally invisible in lib com.android.tools.build:gradle-api, modifications in future releases are expected.

Autoincrement VersionCode with gradle extra properties is not working with Azure Git pipeline

I'm doing automated build number generation via build.gradle using property file.
Changes on the property file is not being pushed in the Git Repository after the assembleRelease has been executed on Azure Devops
private Integer generateBuildNum() {
File buildNumPropsFile = file('../app/src/main/assets/buildnum.properties')
if (buildNumPropsFile.canRead()) {
Properties buildNumProps = new Properties()
buildNumProps.load(new FileInputStream(buildNumPropsFile))
return buildNumProps['VERSION_BUILD'].toInteger()
}
else {
throw new GradleException("Could not read buildnum.properties!")
}
return null
}
private void increaseBuildNum() {
gradle.taskGraph.whenReady { taskGraph ->
println taskGraph.hasTask(assembleRelease)
if (taskGraph.hasTask(assembleRelease)) {
/* when run release task */
File buildNumPropsFile = file('../app/src/main/assets/buildnum.properties')
if (buildNumPropsFile.canRead()) {
Properties buildNumProps = new Properties()
buildNumProps.load(new FileInputStream(buildNumPropsFile))
def build = buildNumProps['VERSION_BUILD'].toInteger() + 1
if(build != null) {
println "*********increaseBuildNum build: "+build
}
buildNumProps['VERSION_BUILD'] = build.toString()
buildNumProps.store(buildNumPropsFile.newWriter(), null)
def buildUpdated = buildNumProps['VERSION_BUILD'].toInteger()
} else {
throw new GradleException("Could not read buildnum.properties!")
}
}
}
}
android {
compileSdkVersion 28
buildToolsVersion "28.0.0"
defaultConfig {
.....
increaseBuildNum()
}
The property file is working when the apk is built on local machine but not on Azure Pipeline. How can I update it on the Git Repo.

builg.gradle: how to execute code only on selected flavor

I declared this function in my Android project build.gradle:
def remoteGitVertsion() {
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parse(new URL("https://api.github.com/repos/github/android/commits"))
assert object instanceof List
object[0].sha
}
And this flavor:
android {
...
productFlavors {
internal {
def lastRemoteVersion = remoteGitVersion()
buildConfigField "String", "LAST_REMOTE_VERSION", "\"" + lastRemoteVersion + "\""
}
...
}
...
}
Now, due to gradle declarative nature, the remoteGitVersion function is executed every time the project is built, it doesn't matter if the build flavor is internal or something else. So, the github API call quota is consumed and, after a little while, I receive a nice forbidden message.
How can I avoid this? Is it possible to execute the function only when the selected flavor is the right one?
Took reference from here:
In Android/Gradle how to define a task that only runs when building specific buildType/buildVariant/productFlavor (v0.10+)
To recap:
1. Wrap your flavor specific logic into a task
task fetchGitSha << {
android.productFlavors.internal {
def lastRemoteVersion = remoteGitVersion()
buildConfigField "String", "LAST_REMOTE_VERSION", "\"" + lastRemoteVersion + "\""
}
}
2. Make the task being called whenever you build your variant, and only then.
You could use assembleInternalDebug to hook into, in your case.
tasks.whenTaskAdded { task ->
if(task.name == 'assembleInternalDebug') {
task.dependsOn fetchGitSha
}
}
3. Make sure to remove the dynamic stuff from your flavor definition
productFlavors {
internal {
# no buildConfigField here
}
}
Hope that helps.

Dynamically generate package name for multi-flavors configuration

I have Gradle Android project that will be used for several customers. Also it will have free and paid version. I realized that it can be achieved by using flavorDimensions. But the problem is that I want to have a method to generate package name depending on selected flavors.
flavorDimensions 'branding', 'version'
productFlavors {
free {
flavorDimension 'version'
}
paid{
flavorDimension 'version'
}
customer1 {
flavorDimension 'branding'
}
customer2 {
flavorDimension 'branding'
}
}
// pseudocode
def getGeneratePackageName() {
if (customer1 && free) {
return 'com.customer1.free'
}
if (customer2 && free) {
return 'com.customer2.free'
}
if (customer1 && paid) {
return 'com.customer1.paid'
}
if (customer2 && paid) {
return 'com.customer2.paid'
}
}
I wonder when do I need to call this method and what variable do I need to set?
Figured it out how to implement this. Groovy code below allows to get flexibility in generation of package names.
buildTypes {
applicationVariants.all { variant ->
def projectFlavorNames = []
variant.productFlavors.each() { flavor ->
projectFlavorNames.add(flavor.name)
}
project.logger.debug('Application variant ' + variant.name + '. Flavor names list: ' + projectFlavorNames)
if (projectFlavorNames.contains('customer1') && projectFlavorNames.contains('variant1')) {
variant.mergedFlavor.packageName = 'com.customer1.variant1'
} else if (projectFlavorNames.contains('customer2') && projectFlavorNames.contains('variant2')) {
variant.mergedFlavor.packageName = 'com.customer2.variant2'
} // else use standard package name
project.logger.debug('Using project name: ' + variant.packageName)
}
// ...
}

Categories

Resources