简体   繁体   中英

How to fix ClassNotFoundException in release build for a fragment in a Dynamic Feature Module using Navigation Architecture Component?

I am trying to build an application with Dynamic Feature modules, without on-demand support.

This is what my app structure looks like:

-app
---MainActivity
-base
---SharedFile
-comments
---CommentsFragment
-posts
---PostsFragment

There are other files in each module too, of course. The debug builds of the application work just fine, and the release builds compile successfully. However, with the release build I encounter a runtime crash with a ClassNotFound Exception for both CommentsFragment and PostsFragment.

This error happened even without enabling proguard on my release builds ( minifyEnabled false ). When I enabled Proguard, the results were the same. I tried adding the following Proguard rules to the app module proguard file (taken from here ):

-keep public class * extends android.app.Activity
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-keep public class * extends android.view.View {
      public <init>(android.content.Context);
      public <init>(android.content.Context, android.util.AttributeSet);
      public <init>(android.content.Context, android.util.AttributeSet, int);
      public void set*(...);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * extends android.content.Context {
    public void *(android.view.View);
    public void *(android.view.MenuItem);
}

-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

The results were still the same: Runtime crash.

Here is my app module build.gradle file:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs.kotlin'

android {
    compileSdkVersion ProjectProps.compileSdk
    defaultConfig {
        applicationId ProjectProps.applicationId
        minSdkVersion ProjectProps.minSdk
        targetSdkVersion ProjectProps.targetSdk
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    dynamicFeatures = [":users", ":posts"]

    packagingOptions {
        exclude 'META-INF/atomicfu.kotlin_module'
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(path: ':base')
    api project(path: ':json-placeholder-repository')

    ...
}

Here is the complete error I get:

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.app.usersmodule.UsersFragment" on path: DexPathList[[zip file "/data/app/com.app-r8BPSasOKhil086vurQf4g==/base.apk"],nativeLibraryDirectories=[/data/app/com.app-r8BPSasOKhil086vurQf4g==/lib/arm64, /system/lib64, /vendor/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at androidx.fragment.app.FragmentFactory.loadClass(FragmentFactory.java:50)
        at androidx.fragment.app.FragmentFactory.loadFragmentClass(FragmentFactory.java:91)

I'm not sure what I'm doing wrong, because the Debug build works just fine.

This seems to be a limitation of the Nav AAC because it checks whether all the classes are present or not at runtime during the graph inflation. I'm not sure why the class is not present. I have disabled Proguard on the project, so none of the code is being stripped away.

The problem turned out to be deploying a signed APK to the device, instead of generating a signed APK using the Android App Bundle format.

Creating a signed AAB, and then converting it to a signed APK using the bundletool from Google creates an APK which has all the Fragments and classes inside it. This works on my device just fine.

Please use an AAB if your project has Dynamic Feature Modules.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM