Multidex - 启用multidex后出现NoClassDefFoundError错误

10

我的应用在pre-21版本上崩溃,出现了java.lang.NoClassDefFoundError app.module.SomeClass错误。

我已经启用了Multidex:

build.gradle:

android {
    defaultConfig {
        ...
        multiDexEnabled true
    }
}

dependencies {
   ...
   implementation "androidx.multidex:multidex:2.0.1"
}

我的Application类:

class App : DaggerApplication() {
    ...
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        MultiDex.install(this)
    }

阅读了有关于在主DEX文件中声明必需的类后,我创建了multidex-config.pro文件以将app.module.**包含在主DEX文件中:

-keep class app.module.** { *; }

并在 build.gradle 文件中进行注册:

android {
  buildTypes {
    debug {
      ...
      multiDexKeepProguard file('multidex-config.pro')
    }
}

我通过检查 build/intermediates/legacy_multidex_main_dex_list/debug/mainDexList.txt 并分析调试 APK (检查 classes.dex 是否包含 app.module.SomeClass)进行确认。

但仍然出现了 java.lang.NoClassDefFoundError app.module.SomeClass 错误。

我还尝试了清除缓存、在不同的机器上运行(仅使用命令行构建,没有使用 Android Studio)、禁用即时运行、指定 javaMaxHeapSize、仅扩展 MultiDexApplication 等。

接下来我可以尝试什么?


请使用以下代码 -keep public class app.module.** { *; } - Mahabub Karim
@MahabubKarim 我试过了,没有效果。 - alashow
为什么在调试配置中要使用 multiDexKeepProguard file('multidex-config.pro') - Archie G. Quiñones
请纠正我,但是在 multidex 之后,您检查 app.module.SomeClass 是否存在,它确实存在吗?这听起来不像是生产问题。您尝试过删除 Proguard 优化吗? - Archie G. Quiñones
@LevonPetrosyan 我尝试在发布版本中禁用Proguard,但是即使在调试版本中也存在崩溃。 - alashow
显示剩余6条评论
6个回答

8
我们在这里进行了更深入的研究: https://issuetracker.google.com/issues/131100011 在早期的一些 Dalvik VMs 中存在一个不幸的 bug,即包私有方法有时会被另一个包中的公共方法错误地覆盖。 如果包私有方法是 final 的,那么就会导致以下类型的错误:
E/dalvikvm: Method Lcom/mycompany/MyViewModel;.clear overrides final Landroidx/lifecycle/ViewModel;.clear 看起来这可能是你遇到的问题。不幸的是,对于这个特定问题,唯一可行的解决方法是将你的“clear”方法重命名为其他名称,以避免遇到这个不幸的 VM bug。

谢谢,这真的很有帮助。 - Max Pinto

4

尝试以下步骤,希望能帮到您

dependencies { 
 compile 'com.android.support:multidex:1.0.1' 
}

配置您的源

在AndroidManifest.xml文件中声明MultiDexApplication类

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:name="android.support.multidex.MultiDexApplication">
</application>

如果我们不能扩展MultiDexApplication,我们可以通过在我们的Application类中覆盖attachBaseContext(Context base)方法来手动安装多个dex文件。

public class HelloMultiDexApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
    }
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

在 app/build.gradle 中配置 dexOptions

android {
    dexOptions {
        incremental true         
        javaMaxHeapSize "4g"
    }
}

在 app/build.gradle 中启用 multidex

android {
 defaultConfig { 
  multiDexEnabled true 
 }
}
afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = ['--multi-dex']
        } else {
            dx.additionalParameters += '--multi-dex'
        }
    }
}
dependencies {
 compile 'com.android.support:multidex:1.0.1' 
}

在根目录的 build.gradle 文件末尾禁用每个模块的预编译处理

subprojects {
    project.plugins.whenPluginAdded { plugin ->
        if ("com.android.build.gradle.AppPlugin".equals(plugin.class.name)) {
            project.android.dexOptions.preDexLibraries = false
        } else if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
            project.android.dexOptions.preDexLibraries = false
        }
    }
}

在gradle.properties中增加gradle jvm构建版本

org.gradle.jvmargs=-Xmx4608M

1
在您的应用gradle文件中添加以下内容:
android {
    ...
    dexOptions {
        jumboMode = true
        javaMaxHeapSize "4g"
     }
     defaultConfig {
         ...

javaMaxHeapSize

指定内存分配池的最大大小(以字节为单位)。此值必须是大于2MB的1024的倍数。附加字母k或K表示千字节,m或M表示兆字节。默认值根据系统配置在运行时选择。


1
尝试更改DaggerApplication指令的顺序:
override fun onCreate() {
    MultiDex.install(this)
    super.onCreate()
}

因为文档中写到:

注意:在MultiDex.install()完成之前,不要通过反射或JNI执行MultiDex.install()或任何其他代码。多DEX跟踪将不会跟随这些调用,从而导致DEX文件之间的错误类分区,从而导致ClassNotFoundException或验证错误。


Multidex.install()移动到那里会导致其他类的实际multidex问题。我尝试从我的app类中删除所有内容,并只扩展自MultiDexApplication - alashow
@alashow 当它只在API 21以下崩溃时,这暗示着库未正确安装...因为后来不再需要该库。DaggerApplication可能与Application的行为不同。Manifest.xml中的<application android:name可能会丢失;这通常定义了Application入口点。 - Martin Zeitler

1
尝试这个。
dexOptions {
            preDexLibraries = false
        }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接