androidkotlinbuild.gradletaskbitrise

Android - A problem was found with the configuration of task - Reason: An input file was expected to be present but it doesn't exist


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:

    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.



Solution

  • 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)
        }