I am using Android's Dynamic delivery for one of my feature. I have separated the code for the feature. I am also using the Navigation component in my project.
I can see dynamicfeature being downloaded from the progress bar and after downloading I am using Navigation component to navigate to Fragment2.
However, when I am trying to navigate from Fragment1 which is in my "app" to Fragment2 which is in my "dynamicfeature" I am getting below exception.
Fatal Exception: android.content.res.Resources$NotFoundException: com.sample.sample.debug.dynamicfeature:navigation/dynamic_feature_nav
at androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.replaceWithIncludedNav(DynamicIncludeGraphNavigator.kt:95)
at androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.navigate(DynamicIncludeGraphNavigator.kt:79)
at androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.navigate(DynamicIncludeGraphNavigator.kt:40)
at androidx.navigation.NavController.navigate(NavController.java:1049)
at androidx.navigation.NavController.navigate(NavController.java:935)
at androidx.navigation.NavController.navigate(NavController.java:868)
at androidx.navigation.NavController.navigate(NavController.java:854)
at androidx.navigation.NavController.navigate(NavController.java:1107)
at com.compass.corelibrary.extensions.NavControllerExtensionsKt.navigateSafeSource(NavControllerExtensions.kt:18)
My app's build.gradle file is like this
apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.firebase-perf'
apply plugin: 'com.heapanalytics.android'
apply plugin: 'kotlin-android'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.compass.jacoco.jacoco-android'
apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'jacoco'
apply plugin: 'kotlinx-serialization'
ext.versionMajor = 2
ext.versionMinor = 35
ext.versionPatch = 0
ext.minimumSdkVersion = 21
android {
compileSdkVersion 31
defaultConfig {
applicationId "com.sample.sample"
minSdkVersion project.ext.minimumSdkVersion
targetSdkVersion 31
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION_NAME
testInstrumentationRunner "com.sample.SampleAndroidJUnitRunner"
ext {
heapEnabled = true
heapAutoInit = true
heapEnvId = HEAP_KEY_GAMMA
}
}
signingConfigs {
beta {
keyAlias "circleci-beta-key-alias"
keyPassword "password"
storeFile file("circleci-beta-key.keystore")
storePassword "password"
}
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
exclude 'META-INF/kotlinx-coroutines-core.kotlin_module'
exclude 'META-INF/kotlinx-serialization-runtime.kotlin_module'
}
flavorDimensions "version"
productFlavors {
debugFlavor {
getIsDefault().set(true)
dimension "version"
applicationIdSuffix ".debug"
matchingFallbacks = ["release", "debug"]
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain_staging",
auth0Scheme: "sample",
facebookLoginProtocolScheme: "@string/fb_login_protocol_scheme_staging",
facebookAppId: "@string/facebook_app_id_staging",
facebookProvider: "@string/facebook_provider_staging"
]
}
alphaFlavor {
dimension "version"
applicationIdSuffix ".alpha"
matchingFallbacks = ["release", "debug"]
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain_staging",
auth0Scheme: "sample",
facebookLoginProtocolScheme: "@string/fb_login_protocol_scheme_staging",
facebookAppId: "@string/facebook_app_id_staging",
facebookProvider: "@string/facebook_provider_staging"
]
}
betaFlavor {
dimension "version"
applicationIdSuffix ".beta"
matchingFallbacks = ["release", "debug"]
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain_staging",
auth0Scheme: "sample",
facebookLoginProtocolScheme: "@string/fb_login_protocol_scheme_staging",
facebookAppId: "@string/facebook_app_id_staging",
facebookProvider: "@string/facebook_provider_staging"
]
}
rcFlavor {
dimension "version"
applicationIdSuffix ".rc"
matchingFallbacks = ["release", "debug"]
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain_staging",
auth0Scheme: "sample",
facebookLoginProtocolScheme: "@string/fb_login_protocol_scheme_staging",
facebookAppId: "@string/facebook_app_id_staging",
facebookProvider: "@string/facebook_provider_staging"
]
}
playStoreFlavor {
dimension "version"
matchingFallbacks = ["release", "debug"]
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain_prod",
auth0Scheme: "compass",
facebookLoginProtocolScheme: "@string/fb_login_protocol_scheme_prod",
facebookAppId: "@string/facebook_app_id_prod",
facebookProvider: "@string/facebook_provider_prod"
]
ext.heapEnvId = HEAP_KEY_PRODUCTION
}
}
buildTypes {
debug {
getIsDefault().set(true)
debuggable true
multiDexEnabled true
signingConfig signingConfigs.beta
matchingFallbacks = ["release", "debug"]
buildConfigField "boolean", "ENABLE_LEAK_CANARY", enableLeakCanary
testCoverageEnabled false
FirebasePerformance {
instrumentationEnabled false
}
}
release {
minifyEnabled true
shrinkResources true
productFlavors.alphaFlavor.signingConfig signingConfigs.beta
productFlavors.betaFlavor.signingConfig signingConfigs.beta
productFlavors.rcFlavor.signingConfig signingConfigs.beta
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
matchingFallbacks = ["release", "debug"]
}
}
dexOptions {
javaMaxHeapSize "4g"
}
testOptions {
unitTests {
includeAndroidResources = true
// Added to ensure timezone is America/New_York for testing purposes
all{
jvmArgs '-Duser.timezone=America/New_York'
systemProperty 'robolectric.dependency.repo.url', 'https://repo1.maven.org/maven2'
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
androidTest { java.srcDirs = ['src/androidTest/kotlin'] }
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
buildFeatures {
viewBinding true
dataBinding true
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.0.5'
}
dynamicFeatures = [':dynamicfeature']
preBuild.dependsOn ktlintFormat
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//All the dependencies are here.
}
My Dynamic Feature build.gradle looks like
apply plugin: 'com.android.dynamic-feature'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
compileSdk 31
defaultConfig {
minSdk 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
getIsDefault().set(true)
debuggable true
matchingFallbacks = ["release", "debug"]
}
release {
matchingFallbacks = ["release", "debug"]
}
}
flavorDimensions "version"
productFlavors {
debugFlavor {
getIsDefault().set(true)
dimension "version"
matchingFallbacks = ["release", "debug"]
}
alphaFlavor {
dimension "version"
matchingFallbacks = ["release", "debug"]
}
betaFlavor {
dimension "version"
matchingFallbacks = ["release", "debug"]
}
rcFlavor {
dimension "version"
matchingFallbacks = ["release", "debug"]
}
playStoreFlavor {
dimension "version"
matchingFallbacks = ["release", "debug"]
}
}
buildFeatures {
viewBinding true
dataBinding true
}
}
dependencies {
implementation project(':app')
}
I am navigating to Fragment2 which is in "dynamicfeature" from Fragment1 which is in "app". Fragment1 is hosted by MainActivity which is in "app".
My app's navigation graph has entry as
<include-dynamic
android:id="@+id/me_dynamic_feature"
app:moduleName="dynamicfeature"
app:graphResName="dynamic_feature_nav"
app:graphPackage="${applicationId}.dynamicfeature" />