无法将请求的类放入单个dex文件中,即使对于先前编译成功的提交也是如此。

11

我刚刚遇到了Android项目方法数量的最大限制,无法构建并显示以下错误消息:

Error: null, Cannot fit requested classes in a single dex file (# methods: 117407 > 65536)

我了解此消息的含义以及如何解决问题(运行proguard、启用multidex等)。我的问题是,我不明白为什么会突然出现这个消息-我正在删除一些过时的代码,点击“构建”按钮,然后就出现了这个消息。

问题1:即使我没有添加任何库依赖项,我的方法数(根据错误消息为117407)怎么可能突然超过了限制(65536)?实际上,我删除了代码,但突然间多了约5万个方法?

现在情况变得非常奇怪:我想分析APK以找出问题所在,但我不能构建它。因此,我决定恢复到昨天的代码版本(昨天绝对可以成功构建-我有安装在手机上的应用程序可证明!),但我仍然收到构建错误消息。我不明白这是怎么回事。我尝试还原到几天前,结果还是一样(克隆新存储库并检查较早的提交)。

所以,问题2:我如何在完全相同的代码中获得这个构建错误,而昨天它却可以顺利构建没有出现错误?

我唯一能想到的是,我作为依赖项使用的库突然增加了大小-但我在gradle build中声明了每个库的特定版本,例如:

// RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'

所以,我的依赖关系肯定没有改变吧?

非常感谢任何帮助我找到解决方法的建议。我已经尝试过清理项目,并在Android Studio中无效化缓存/重启。我真的不想在我的调试版本上启用multidex或运行proguard。

以下是完整的build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "XXXXXXXXX"
    minSdkVersion 19
    targetSdkVersion 28
    versionCode 1
    versionName "0.1"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    vectorDrawables.useSupportLibrary = true  // see https://developer.android.com/studio/write/vector-asset-studio#sloption
}
buildTypes {
    release {
        minifyEnabled false
        // Do code shrinking!
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

// Core stuff
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-vector-drawable:28.0.0'
implementation 'com.google.android.gms:play-services-wearable:16.0.1'

// Dagger
implementation 'com.google.dagger:dagger:2.21'
kapt 'com.google.dagger:dagger-compiler:2.21'
// Dagger for Android
implementation 'com.google.dagger:dagger-android:2.21'
implementation 'com.google.dagger:dagger-android-support:2.21' // if you use the support libraries
kapt 'com.google.dagger:dagger-android-processor:2.21'

// Constraint layout
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

// Associated WearOS project
wearApp project(':wear')

// Common library project
implementation project(':common')

// These were added to resolve gradle error on the 'com.android.support:appcompat-v7:28.0.0' implementation:
// All com.android.support libraries must use the exact same version specification (mixing versions can lead to
// runtime crashes). Found versions 28.0.0, 26.1.0. Examples include com.android.support:animated-vector-drawable:28.0.0
// and com.android.support:support-media-compat:26.1.0
// This seems to be related to linking the wear project. If the wear project was not linked, the error went away.
implementation 'com.android.support:support-media-compat:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'

// RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
// Retrofit RxJava
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
// Retrofit logging:
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'

// Room
def room_version = "1.1.1"
implementation "android.arch.persistence.room:runtime:$room_version"
implementation "android.arch.persistence.room:common:$room_version"
implementation "android.arch.persistence.room:rxjava2:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"

// For modern time handling (java.time requires API 26 or higher)
implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1'

// Graphing
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'

// Dropbox
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.11'

// OpenCSV
implementation 'com.opencsv:opencsv:4.5'

}

编辑

启用multidex后,使用Android Studio分析APK时,以下TLD下显示了一些重要的依赖项(我不确定是否应该查看定义或引用的方法编号?):

  • com.dropbox:26000个已定义的方法,34000个已引用的方法
  • com.android(主要是支持库):18700个已定义,24600个已引用
  • org.apache(commons、log等):15000个已定义,15700个已引用

这些单独就已经接近极限了。但我仍然不理解为什么会突然发生这种情况 :( 如果我没有添加任何库,这些数字应该不会改变,对吗?


返回:

编辑

启用multidex后,使用Android Studio分析APK时,以下TLD下显示了一些重要的依赖项(我不确定是否应该查看定义或引用的方法编号?):

  • com.dropbox:26000个已定义的方法,34000个已引用的方法
  • com.android(主要是支持库):18700个已定义,24600个已引用
  • org.apache(commons、log等):15000个已定义,15700个已引用

这些单独就已经超过了极限。但我仍然不理解为什么会突然发生这种情况 :( 如果我没有添加任何库,这些数字应该不会改变,对吗?


你能否发布你的整个build.gradle文件(如果你愿意,可以去除标识)? - Andres S
我已经添加了有关该项目的build.gradle文件。它引用了一个名为“common”的常用库项目和一个链接的WearOS项目。 - James Allen
@JamesAllen 这个错误来自于d8/r8,它在Android Studio 3.1中成为了默认编译器。可能这个新的编译器与dx/proguard工具链的行为不同(也许你之前的版本是用dx/proguard构建的)。你可以尝试使用android.enableD8=false回退到dx并查看是否出现相同的错误。 - Alex Lipov
1
今天我也遇到了这个问题。即使回滚到先前的提交也没有用。我还发现,如果只是在调试或发布模式下运行应用程序,它就能正常工作。但是从构建菜单中运行“构建”会导致此问题。什么鬼??我的应用程序非常小,没有大量依赖项。 - Johann
12个回答

21

将以下内容添加到您的 gradle (Module: app) 中 >> multiDexEnabled true

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

然后重建项目,在菜单中点击 => Build>Rebuild Project。


谢谢您的建议,但我已经启用了multidex。这不是我的问题。正如我在开头所说,“我理解消息的含义以及如何解决它(运行proguard,启用multidex等)。我的问题是我不明白为什么突然收到这个消息”。 - James Allen
1
那个解决方案帮助我解决了添加implementation 'com.google.zxing:core:3.4.0'时的问题。谢谢 @Driss Baidou。 - Mark Delphi

5

在查看您的整个构建 Gradle 文件后,您的问题明显源于依赖项!试图清理它们并尽可能多地删除您不使用的依赖项。很有可能您非常接近极限,其中任何一个依赖项都可能使用旧版本进行了缓存。您可以尝试删除整个构建文件夹(以及清理 Gradle 缓存),但我相当确定问题不会消失。

如果所有这些依赖项都是必需的,那么您将不得不选择您提到的路线,即多 dex 或 minify 调试构建。多 dex 应该没问题,不会引起任何意外问题,而最小化则会减慢构建速度并可能导致 Android Studio 不稳定(特别是即时运行/应用更改!)

祝你好运,从这一点中学到的是要保持干净和精确的依赖关系,仅在绝对需要时添加,如果其他所有方法都失败了,则多 dex 是您的朋友。


谢谢你的帮助!我只是试图理解为什么方法计数突然增加到接近限制的两倍。我对你的这句话“任何这些依赖项都可能使用旧版本进行缓存”非常感兴趣 - 这听起来像一个可能的答案,你能进一步解释一下吗? - James Allen
Gradle/AS 缓存相当大。可能缓存出现了问题(或者出现了奇怪的情况),并且低估了没有影响到您代码的方法(甚至截断了一些依赖项)。当缓存过期时,或者您强制重新构建时,Gradle "修复"自己并带来问题。您可以尝试清除所有内容(所有构建文件夹、所有 Gradle 遗留文件,以及所有链接项目),看看是否有任何变化,但我对此不太确定。 - Andres S
好的,谢谢 - 那应该就是了。我看不出其他原因。 - James Allen
请注意,Android支持依赖项,甚至可能更新了kotlin插件,并导致未删除重复方法引用(永远不会被删除)的更改,因此尽管这个错误可能优先级较低,因为它不会造成任何(大)问题。Gradle生态系统是一堆优化的混乱,不幸的是,要理解它需要数年的深入研究。我每天都会遇到这些问题,唯一帮助我的事情就是在依赖关系失控并防止随机依赖添加时进行清理和组织依赖关系。 - Andres S

3

他们给你的答案都不够详细。问题在于 Multidex。你需要在应用 gradle 中添加该库:

implementation 'com.android.support:multidex:1.0.3'

之后,您应在应用 gradle 的 defaultConfig 中添加以下内容:

multiDexEnabled true

1
这很有帮助,谢谢。如果使用androidx,请使用implementation 'androidx.multidex:multidex:2.0.1'代替上面的内容。 - Masiorama

1

来自Android文档:

“如果您的minSdkVersion设置为21或更高版本,则默认情况下启用multidex,您不需要multidex支持库。”

作为手动启用multidex的替代方法,如果可能的话,您可以简单地增加minSdkVersion。


0
在build.gradle应用程序中
implementation 'com.android.support:multidex:2.0.1'

android {
    multiDexEnabled true

}


0
根据您的问题,我不得不删除 build 文件夹和 *.iml 文件(即 Android Studio 项目文件),然后重新创建项目、构建,这样一切就恢复正常了。

0

我遇到了同样的问题,解决方法是在“文件” -> “设置” -> “构建、执行、部署” -> “即时运行”下启用即时运行,这解决了我的问题。希望对你有所帮助。


0

社区维基

只需要增加这个minSdkVersion,targetSdkVersion的版本:

旧版:

defaultConfig { minSdkVersion 19 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName }

新版:

defaultConfig { minSdkVersion 21 targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName }

还有这个compileSdkVersion:

旧版:

android { compileSdkVersion 28}

新版:

android { compileSdkVersion 29}


0
我建议使用multidex构建应用程序,然后从新的apk的多个dex文件中提取方法ID,还要从旧的单dex apk中提取方法ID,并比较这两个列表。
大致上,就像这样:
baksmali list dex new.apk
baksmali list method new.apk/classes.dex > new.list
baksmali list method new.apk/classes2.dex >> new.list
sort new.list > new.sorted.list

baksmali list method old.apk > old.list
diff new.sorted.list old.list

虽然,如果您正在使用Proguard,则可能需要找出一些方法在比较列表之前应用反向Proguard名称混淆。


谢谢,不过很遗憾我没有旧版 APK 来进行比较,而且我似乎也无法构建我的代码的早期版本,这是奇怪的地方。最终我启用了 multidex,然后使用 Android Studio 分析了 APK - 请参见更新的问题 :) - James Allen

0

阅读了您的问题后,我只能建议尝试在此之后使缓存无效并重新启动,并强制刷新您的依赖项。

./gradlew build --refresh-dependencies

谢谢,不幸的是这没有解决问题。 - James Allen

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