I have an android project, and I recently updated to Kotlin 1.9, Java 17, and Gradle 8.2.
I have been able to successfully update and build everything on my machine, but when I try to build the app in bitrise.io, the build fails with this exception:
FAILURE: Build failed with an exception.
* What went wrong:
A problem was found with the configuration of task ':apps:produceAppnameReleaseBundleIdeListingFile' (type 'BundleIdeModelProducerTask').
- In plugin 'com.android.internal.version-check' type 'com.android.build.gradle.internal.tasks.BundleIdeModelProducerTask' property 'finalBundleFile' specifies file
'/bitrise/src/droid/apps/build/outputs/bundle/appnameRelease/apps-appname-
release.aab' which doesn't exist.
Reason: An input file was expected to be present but it doesn't exist.
Possible solutions:
1. Make sure the file exists before the task is called.
2. Make sure that the task which produces the file is declared as an input.
What I have tried:
./gradlew app:assembleRelease -Pandroid.debug.obsoleteApi=true --dry-run
in the terminal to determine which step creates the .aab
file
build.gradle
file to the section that processes tasks: android {
...
applicationVariants.configureEach { variant ->
...
afterEvaluate {
tasks.matching { it.name == "produce${variant.name.capitalize()}BundleIdeListingFile" }.configureEach { task ->
task.dependsOn tasks.named("copy${variant.name.capitalize()}Bundle")
}
tasks.named("copy${variant.name.capitalize()}Bundle").configure { task ->
task.dependsOn tasks.named("bundle${variant.name.capitalize()}")
}
tasks.named("produce${variant.name.capitalize()}BundleIdeListingFile").configure { task ->
task.mustRunAfter tasks.named("copy${variant.name.capitalize()}Bundle")
}
}
}
There are hundreds of tasks that are generated during this process, but I can't find a way to determine which (if any) are the tasks that create the .aab
Perhaps it is generated somewhere else, but I have not found a suitable solution that will resolve this.
If you have an idea and need more info, let me know and I will post more code.
Update #1 The filepath indicated shows: /bitrise/src/droid/apps/build/outputs/bundle/appnameRelease/apps-appname- release.aab
However, that is not the naming scheme of the file. The file that is generated is named: appname-6.315-99999-QA.aab
in the pattern: variantProductFlavor}-{version}-{build number}-{variantBuildType}
But I'm not sure how to change that file type. It appears that this has been addressed in the copyBundleTask
, and I also added the line:
if (output.hasProperty('finalBundleFile')) {
output.finalBundleFile.set(file("${buildDir}/outputs/bundle/${variantName}/${artifactName}.aab"))
}
This doesn't seem to have changed the value for finalBundleFile
Update #2
After successfully renaming and producing the .aab
it seems that the bundle is only an empty file that does not actually do anything.
The file is created and renamed correctly, but the bundle is 0b and does nothing.
Currently trying to figure out why the bundle is suddenly no longer created.
Here is the whole code section:
productFlavors {
project.file('src').list({ d, f -> !'main'.equals(f) && !'test'.equals(f) && !f.startsWith('.') }).each { flavorName ->
def projectPath = "${project.projectDir}/src/${flavorName}"
def packageName = PackageUtil.getPackageNameFromBrandFile(projectPath)
// HERE IS WHERE THE APK SHOULD BE SIGNED
signingConfigs.each { config ->
if (config.name.equalsIgnoreCase(flavorName)) {
"${flavorName}" {
applicationId packageName
resValue "string", "PACKAGE_NAME", packageName
resValue "string", "SHORT_CODE", flavorName
dimension 'appnamePlatform'
matchingFallbacks = ['appnamePlatform']
// Set the signingConfig in the flavor rather than build type. To override,
// set the signingConfig in the buildTypes section
signingConfig config
}
}
}
task("publish${flavorName.capitalize()}", type: Task, { publishTask ->
if (makeRelease && !URLReplaced && !makeQA) {
if (makeAPK) {
publishTask.dependsOn "assemble${flavorName.capitalize()}Release"
}
if (makeBundle) {
publishTask.dependsOn "bundle${flavorName.capitalize()}Release"
}
}
if (makeQA && makeAPK) {
logger.lifecycle("Making QA APK because makeQA and makeAPK are true")
publishTask.dependsOn "assemble${flavorName.capitalize()}Qa"
} else if (URLReplaced) {
logger.lifecycle("Making QA APK since base or chat url\'s were overridden")
publishTask.dependsOn "assemble${flavorName.capitalize()}Qa"
}
publishTask.dependsOn "signingReport"
group = "publish"
publishTask.doFirst {
project.CURRENT_FLAVOR = flavorName.capitalize()
logProjectInfo(project)
}
publishTask.finalizedBy(uploadBuildFiles)
})
}
}
applicationVariants.configureEach { variant ->
def variantMatcher = variant.name =~ /([a-z0-9]+)([A-Z][a-z]+)/
if (!variantMatcher.matches()) {
logger.lifecycle('UNKNOWN VARIANT CANNOT CONFIGURE VERSIONED UPLOAD TASK')
return
}
def variantProductFlavor = variantMatcher.group(1)
def variantBuildType = variantMatcher.group(2)
if (!variantBuildType.equalsIgnoreCase('Debug')) {
def projectPath = "${project.projectDir}/src/${variantProductFlavor}"
def newVersionCode = VersionUtil.getVersionCode(project, variantProductFlavor)
def newVersionName = VersionUtil.getVersionName(project, variantProductFlavor)
def suffix = variantBuildType.equalsIgnoreCase("Qa") ? "-QA" : ""
def artifactName = "${variantProductFlavor}-${newVersionName}-${newVersionCode}${suffix}"
variant.outputs.configureEach {
outputFileName = "${artifactName}.apk"
}
variant.outputs.each { output ->
// Assign dynamic build variables only in Qa and Release builds (to speed up build times)
output.versionCodeOverride = newVersionCode
output.versionNameOverride = newVersionName
Task copyBundleTask = project.task("copy${variant.name.capitalize()}Bundle", type: Copy) {
group = "modify"
duplicatesStrategy = 'include'
def path = "${buildDir}/outputs/bundle/${variant.name}/"
from path
into path
include "**.aab"
rename { String fileName ->
"${artifactName}.aab"
}
doLast {
delete fileTree(path) {
include "**.aab"
exclude "${artifactName}.aab"
}
}
}
Task renameMappingTask = project.task("rename${variant.name.capitalize()}Mapping", type: Copy) {
group = "modify"
duplicatesStrategy = 'include'
def path = "${buildDir}/outputs/mapping/${variantProductFlavor}/${variantBuildType.toLowerCase()}/"
from path
into path
include "**.txt"
rename { String fileName ->
"${artifactName}-mapping.txt"
}
doLast {
delete fileTree(path) {
include "mapping.txt"
}
}
}
// Run the copy tasks once the assemble/bundle tasks are finished
variant.assembleProvider.get().finalizedBy renameMappingTask
project.getTasksByName("bundle${variant.name.capitalize()}", false)
.first().finalizedBy([copyBundleTask, renameMappingTask])
output.processManifestProvider.get().doLast {
try {
def outputDir = multiApkManifestOutputDirectory.get().asFile
File manifestPath = new File(outputDir, "/AndroidManifest.xml")
// Stores the contents of the manifest.
//def manifestContent = file(manifestPath).getText()
def newFileContents = ManifestUtil.generateDeepLinkIntent(
new File(projectPath),
manifestPath.getText('UTF-8')
)
manifestPath.write(newFileContents, 'UTF-8')
} catch (Exception e) {
logger.warn("Failed to process manifest for variant", e)
}
}
}
tasks.configureEach { task ->
task.doLast {
if (task.name.contains("bundle")) {
println "Task ${task.name} produces output: ${task.outputs.files.files}"
}
}
}
afterEvaluate {
tasks.matching { it.name == "produce${variant.name.capitalize()}BundleIdeListingFile" }.configureEach { task ->
task.dependsOn tasks.named("copy${variant.name.capitalize()}Bundle")
task.mustRunAfter tasks.named("copy${variant.name.capitalize()}Bundle")
}
tasks.named("copy${variant.name.capitalize()}Bundle").configure { task ->
task.dependsOn tasks.named("bundle${variant.name.capitalize()}")
}
}
logger.lifecycle("Configuring [" +
"Project: ${project.name}, " +
"Flavor: ${variantProductFlavor}, " +
"Type: ${variantBuildType}, " +
"Output: $artifactName")
}
}
Bitrise Configuration YAML
---
format_version: '6'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: other
workflows:
deploy-android-2024:
steps:
- activate-ssh-key@4:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
inputs:
- verbose: 'true'
- activate-ssh-key@4:
run_if: '{{getenv "SSH_KEY_FOR_QA_DL_PAGE" | ne ""}}'
inputs:
- verbose: 'true'
- ssh_rsa_private_key: "$SSH_KEY_FOR_QA_DL_PAGE"
- ssh_key_save_path: "$HOME/.ssh/id_rsa"
- is_remove_other_identities: 'false'
- script@1:
inputs:
- content: |-
#!/usr/bin/env bash
# fail if any commands fails
set -e
# debug log
set -x
echo "Adding dl.appName.com to Known-Hosts"
mkdir -p $HOME/.ssh/
touch $HOME/.ssh/known_hosts
ssh-keyscan -t rsa dl.appName.com >> $HOME/.ssh/known_hosts
title: Add dl.appName.com to SSH's Known Hosts
- authenticate-with-github-oauth@0:
inputs:
- access_token: "$GITHUB_PERSONAL_TOKEN"
- username: "$GITHUB_USER_NAME"
- git-clone@8:
inputs:
- reset_repository: 'Yes'
- clone_into_dir: "$BITRISE_SOURCE_DIR/droid"
- install-missing-android-tools: {}
- script@1:
title: Set Default Environment Variables
inputs:
- content: |-
#!/usr/bin/env bash
# fail if any commands fails
set -e
# debug log
set -x
if [ -z "$CUSTOM_BUILD_NUMBER" ] ; then
envman add --key CUSTOM_BUILD_NUMBER --value "$DEFAULT_BUILD_NUMBER"
fi
if [ -z "$SHORTCODE" ] ; then
envman add --key SHORTCODE --value "$DEFAULT_SHORTCODE"
fi
envman add --key SHORTCODE_CAP --value "${SHORTCODE^}"
#if [ -z "$VERSION" ] ; then
# envman add --key VERSION --value "$DEFAULT_VERSION"
#fi
if [ -z "$CHAT_SERVER_OVERRIDE" ] ; then
envman add --key CHAT_SERVER_OVERRIDE --value "$DEFAULT_CHAT_SERVER_OVERRIDE"
fi
if [ -z "$REST_SERVER_OVERRIDE" ] ; then
envman add --key REST_SERVER_OVERRIDE --value "$DEFAULT_REST_SERVER_OVERRIDE"
fi
if [ -z "$API_SERVER_OVERRIDE" ] ; then
envman add --key API_SERVER_OVERRIDE --value "$DEFAULT_API_SERVER_OVERRIDE"
fi
if [ -z "$FEED_SERVER_OVERRIDE" ] ; then
envman add --key FEED_SERVER_OVERRIDE --value "$DEFAULT_FEED_SERVER_OVERRIDE"
fi
if [ -z "$GRAPHQL_SERVER_OVERRIDE" ] ; then
envman add --key GRAPHQL_SERVER_OVERRIDE --value "$DEFAULT_GRAPHQL_SERVER_OVERRIDE"
fi
- fastlane@3:
inputs:
- work_dir: "$BITRISE_SOURCE_DIR/droid"
- lane: android pull_assets shortcode:$SHORTCODE rest_server_override:'$REST_SERVER_OVERRIDE'
- change-workdir@1:
inputs:
- path: "$ANDROID_REPO_PATH"
title: cd $ANDROID_REPO_PATH
- gradle-runner@2.0:
inputs:
- gradle_task: publish$SHORTCODE_CAP
- gradle_options: "--stacktrace --scan -PbuildNumber=$CUSTOM_BUILD_NUMBER
-PbaseUrlReplacement=$REST_SERVER_OVERRIDE -PchatUrlReplacement=$CHAT_SERVER_OVERRIDE
-PapiUrlReplacement=$API_SERVER_OVERRIDE -PfeedUrlReplacement=$FEED_SERVER_OVERRIDE
-PmakeAPK=true -PmakeBundle=true -PmakeRelease=true -PmakeQa=$MAKE_QA
-Penable-performance-plugin"
- cache_level: all
- app_file_exclude_filter: |-
*apps-*.apk
*apps-*.aab
*Test*.apk
- mapping_file_include_filter: "*/*mapping.txt"
- gradle_file: "$ANDROID_REPO_PATH/build.gradle"
title: Build App
- script@1:
inputs:
- content: |-
#!/usr/bin/env bash
# fail if any commands fails
set -e
# debug log
set -x
cd $ANDROID_REPO_PATH
cp apps/src/$SHORTCODE/res/xml/brand.xml $BITRISE_DEPLOY_DIR
# Delete copied files
rm -rf build/outputs
rm -rf apps/build/outputs
echo "Copied the following APK files:"
cd $BITRISE_DEPLOY_DIR
ls -la *.xml
title: Save brand file
is_always_run: true
- deploy-to-bitrise-io@2:
inputs:
- generate_universal_apk_if_none: 'false'
- bundletool_version: 1.15.4
- is_compress: 'true'
- debug_mode: 'true'
- notify_email_list: "$QA_EMAIL"
title: Save Apps, Logs, Artifacts
after_run:
- post-jira-comment
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: standard
app:
envs:
- DEFAULT_BUILD_NUMBER: "$BITRISE_BUILD_NUMBER"
- DEFAULT_SHORTCODE: appName
- opts:
is_expand: false
DEFAULT_REST_SERVER_OVERRIDE: ''
- opts:
is_expand: false
DEFAULT_CHAT_SERVER_OVERRIDE: ''
- GRADLEW_PATH: "$BITRISE_SOURCE_DIR/droid/gradlew"
- ANDROID_REPO_PATH: "$BITRISE_SOURCE_DIR/droid"
- DEFAULT_VERSION: ''
opts:
is_expand: false
- opts:
is_expand: false
DEFAULT_API_SERVER_OVERRIDE: ''
- opts:
is_expand: false
DEFAULT_FEED_SERVER_OVERRIDE: ''
- opts:
is_expand: false
DEFAULT_GRAPHQL_SERVER_OVERRIDE: ''
meta:
bitrise.io:
machine_type: standard
stack: linux-docker-android-20.04
machine_type_id: standard
trigger_map:
- pull_request_target_branch: "*"
enabled: false
type: pull_request
workflow: UnitTests
Update #3
There is less than a day on this bounty. I would love to reward someone if I can get an answer!!
The problem seems to be with a property from a gradle task that can't be renamed from its default name.
A problem was found with the configuration of task ':apps:produceAppnameReleaseBundleIdeListingFile' (type 'BundleIdeModelProducerTask').
In plugin 'com.android.internal.version-check' type 'com.android.build.gradle.internal.tasks.BundleIdeModelProducerTask' property 'finalBundleFile' specifies file '/Users/me/appname/droid/apps/build/outputs/bundle/appNameRelease/apps-appname-release.aab' which doesn't exist.
The file apps-appname-release.aab
is renamed in a previous step.
I have not been able to figure out how to have this step look for the correct file name.
I found the answer in another post: Link To Answer - How to change the generated filename for App Bundles with Gradle?
It seemed no matter how I renamed the bundle the ProduceBudleIdeListingFile
step (type 'BundleIdeModelProducerTask') would always append an unwanted string to the name of the file.
This was the final task change that resolved the issue:
import com.android.build.gradle.internal.tasks.FinalizeBundleTask
tasks.named("sign${variant.name.capitalize()}Bundle", FinalizeBundleTask) { task ->
task.dependsOn tasks.named("copy${variantProductFlavor.capitalize()}${variantBuildType}Bundle")
def aabPackageName = "${artifactName}.aab"
def file = finalBundleFile.asFile.get()
def finalFile = new File(file.parentFile, aabPackageName)
finalBundleFile.set(finalFile)
}