androidgradleandroid-manifestkoindynamic-feature-module

Build fails with 'task :features:catalog:createDebugCompatibleScreenManifests FAILED' while refactoring to dynamic feature modules on android


Once I introduced dynamic feature modules into my app, I was able to successfully refactor feature one (orders), build and deploy. But on refactoring the second module, i.e moving files and resources to that module, I get this error on build:


Execution failed for task ':features:catalog:createDebugCompatibleScreenManifests'.
> Failed to calculate the value of task ':features:catalog:createDebugCompatibleScreenManifests' property 'applicationId'.
   > Failed to query the value of property 'testedApplicationId'.
      > Collection has more than one element.

I have tried the following fixes:

  1. invalidate cache
  2. reclone project
  3. ensure all gradle files are identical (except for applicationId bit)
  4. checked that there are no errors in the manifest files
  5. confirmed that no two modules share the same application ID.
  6. rebase the project to the last working commit.

Any pointers as to what is causing this build issue?

Other info: I'm using dependency injection with koin.

App/Main module manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.app">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <uses-feature
        android:name="android.hardware.camera2"
        android:required="false" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:name=".ExampleApp"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="AllowBackup,GoogleAppIndexingWarning">

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />
        <meta-data
            android:name="firebase_crashlytics_collection_enabled"
            android:value="${crashlyticsCollectionEnabled}" />

        <activity android:name="com.kyosk.app.ui.fragment.login.LoginActivity" />

        <activity android:name="com.kyosk.app.ui.activity.SplashActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name="com.kyosk.app.ui.activity.Home" />

        <service
            android:name=".service.MessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <service
            android:name=".location.services.LocationUpdatesService"
            android:exported="false" />
        <service
            android:name=".location.services.MapsLocationUpdatesService"
            android:exported="false" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

</manifest>

App/Main module build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-kapt'

apply plugin: "androidx.navigation.safeargs.kotlin"

apply plugin: 'realm-android'

apply plugin: 'com.google.gms.google-services'

apply plugin: 'com.google.firebase.crashlytics'

apply plugin: (BuildPlugins.dependencyUpdateChecker)

android {

    compileSdkVersion AndroidSDK.compileSDKVersion
    buildToolsVersion Versions.buildTools

    defaultConfig {
        applicationId "com.example.app"
        minSdkVersion AndroidSDK.minimumSDKVersion
        targetSdkVersion AndroidSDK.targetSDKVersion
        versionCode Versions.versionCode
        versionName Versions.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        debug {
            manifestPlaceholders = [crashlyticsCollectionEnabled: "false"]
            applicationIdSuffix(".debug")
            versionNameSuffix("-debug")
            buildConfigField("String", "BASE_URL", debug_url)
        }

        staging {
            initWith(release)
            manifestPlaceholders = [crashlyticsCollectionEnabled: "false"]
            applicationIdSuffix(".staging")
            versionNameSuffix("-staging")
            buildConfigField("String", "BASE_URL", staging_url)
        }

        release {
            manifestPlaceholders = [crashlyticsCollectionEnabled: "true"]
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField("String", "BASE_URL", production_url)
        }
    }

    buildFeatures {
        viewBinding = true
        dataBinding = true
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }

    kapt {
        correctErrorTypes = true
    }

    dynamicFeatures = [':features:kiosks', ':features:catalog', ':features:checkout', ':features:summary', ':features:orders']
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation Libraries.kotlinStandardLibrary
    implementation Libraries.appCompat
    implementation Libraries.constraintLayout
    api Libraries.materialComponents
    implementation Libraries.navigationFragment
    implementation Libraries.navigationUI

    implementation Libraries.preferences

    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

    //firebase libs
    implementation Libraries.firebaseMessaging
    implementation Libraries.firebaseConfig
    // Recommended: Add the Firebase SDK for Google Analytics.
    implementation Libraries.firebaseAnalytics
    implementation Libraries.firebaseCrashlytics

    // DI
    api Libraries.koinAndroid
    api Libraries.koinLifecycle
    api Libraries.koinViewmodel

    //maps
    implementation 'com.google.android.gms:play-services-maps:17.0.0'

    //own modules
    implementation project(path: ':location-services')
    implementation project(path: ':network')
    api project(path: ':helpers')

    //glide
    implementation 'com.github.bumptech.glide:glide:4.11.0'

    kapt 'com.github.bumptech.glide:compiler:4.11.0'

    //loading button
    api Libraries.buttonProgress

    //pagination lib
    implementation Libraries.jdroidCoder

    //EventBus
    api Libraries.eventBus

    //logging
    api Libraries.timber

    //anko
    api Libraries.ankoDesign
    api Libraries.ankoCommons

    //play core library
    implementation(Libraries.playCore)
    implementation(Libraries.playCorektx)

    // paris for applying styles to views dynamically
    implementation 'com.airbnb.android:paris:1.7.2'

    // lottie for animations
    implementation 'com.airbnb.android:lottie:3.5.0'

    // Okhttp Profiler
    implementation Libraries.loggingInterceptor

    // Test libs
    testImplementation(TestLibraries.junit4)
    androidTestImplementation(TestLibraries.androidX)
    androidTestImplementation(TestLibraries.espresso)
    androidTestImplementation(TestLibraries.annotationLib)
}

Feature Module 1(orders) manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    package="com.example.app.orders">

    <dist:module
        dist:instant="false"
        dist:title="@string/title_orders">
        <dist:delivery>
            <dist:install-time />
        </dist:delivery>
        <dist:fusing dist:include="true" />
    </dist:module>
</manifest>

Feature 1 (orders) build.gradle

apply plugin: 'com.android.dynamic-feature'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: (BuildPlugins.dependencyUpdateChecker)


android {
    compileSdkVersion AndroidSDK.compileSDKVersion
    buildToolsVersion Versions.buildTools

    defaultConfig {
        applicationId "com.example.app.orders"
        minSdkVersion AndroidSDK.minimumSDKVersion
        targetSdkVersion AndroidSDK.targetSDKVersion
        versionCode Versions.versionCode
        versionName Versions.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        debug {}
        staging {}
        release {}
    }

    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    buildFeatures {
        viewBinding = true
        dataBinding = true
    }
}

dependencies {
    implementation project(":app")
    implementation project(path: ':network')
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation Libraries.kotlinStandardLibrary
    implementation Libraries.ktxCore
    implementation Libraries.appCompat
    implementation Libraries.constraintLayout
    implementation Libraries.materialComponents
    implementation Libraries.navigationFragment
    implementation Libraries.navigationUI

    implementation Libraries.buttonProgress
    implementation Libraries.ankoDesign
    implementation Libraries.ankoCommons

    implementation(Libraries.coroutinesAndroid)

    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

    // Test libs
    testImplementation(TestLibraries.junit4)
    androidTestImplementation(TestLibraries.androidX)
    androidTestImplementation(TestLibraries.espresso)
    androidTestImplementation(TestLibraries.annotationLib)
}

Solution

  • The issue ended up being a library I had imported.

    The library had plugin apply plugin: 'com.android.application' instead of apply plugin: 'com.android.library'

    As such, gradle build task was looking for applicationId and applicationName in the manifest, which was not there.

    Oops, developer error.