[Flutter]解决ERROR:D8: Cannot fit requested classes in a single dex file的问题
最近在学习开发Flutter项目时遇到了一个问题,具体的异常信息如下:
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
ERROR:D8: Cannot fit requested classes in a single dex file (# methods: 65853 > 65536)
com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
The number of method references in a .dex file cannot exceed 64K.
Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:151)
at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:138)
at com.android.build.gradle.internal.tasks.DexMergingWorkAction.merge(DexMergingTask.kt:859)
at com.android.build.gradle.internal.tasks.DexMergingWorkAction.run(DexMergingTask.kt:805)
at com.android.build.gradle.internal.profile.ProfileAwareWorkAction.execute(ProfileAwareWorkAction.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$2(DefaultWorkerExecutor.java:205)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:114)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete, position: null
at Version.fakeStackEntry(Version_3.2.47.java:0)
at com.android.tools.r8.internal.ci.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:68)
at com.android.tools.r8.internal.ci.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:28)
at com.android.tools.r8.internal.ci.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:27)
at com.android.tools.r8.internal.ci.b(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:3)
at com.android.tools.r8.D8.run(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:11)
at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:136)
... 38 more
Caused by: com.android.tools.r8.internal.a: Cannot fit requested classes in a single dex file (# methods: 65853 > 65536)
at com.android.tools.r8.internal.tQ.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:14)
at com.android.tools.r8.internal.tQ.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:22)
at com.android.tools.r8.internal.fZ.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:560)
at com.android.tools.r8.internal.bZ.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:7)
at com.android.tools.r8.internal.o2.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:383)
at com.android.tools.r8.internal.o2.c(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:54)
at com.android.tools.r8.D8.d(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:763)
at com.android.tools.r8.D8.b(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:1)
at com.android.tools.r8.internal.ci.a(R8_3.2.47_ebadcf1df6fbed6005a238b8399b2cd411e753b60758261060e399f9498872a5:24)
... 41 more
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeExtDexDebug'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.DexMergingTaskDelegate
> There was a failure while executing work items
> A failure occurred while executing com.android.build.gradle.internal.tasks.DexMergingWorkAction
> com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
The number of method references in a .dex file cannot exceed 64K.
Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 33s
在异常信息中让我们去这个地方 https://developer.android.com/tools/building/multidex.html
解决问题。(以上地址已经失效了,新的地址是:https://developer.android.com/build/multidex)
查阅资料后知道了,Android 5.0 及更高版本的 MultiDex 支持,而低版本需要手动操作配置一些东西。
- Android 5.0 之前版本的 MultiDex 支持
Android 5.0(API 级别 21)之前的平台版本使用 Dalvik 运行时执行应用代码。默认情况下,Dalvik 将应用限制为每个 APK 只能使用一个 classes.dex 字节码文件。为了绕过这一限制,您可以向模块级 build.gradle 文件中添加 MultiDex 库:
...
dependencies {
def multidex_version = "2.0.1"
implementation "androidx.multidex:multidex:$multidex_version"
}
...
如需查看此库的当前版本,请参阅版本页面中有关 MultiDex 的信息。
如果您使用的不是 AndroidX,请改为添加以下已弃用的支持库依赖项:
...
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
...
- Android 5.0 及更高版本的 MultiDex 支持
Android 5.0(API 级别 21)及更高版本使用名为 ART 的运行时,它本身支持从 APK 文件加载多个 DEX 文件。ART 在应用安装时执行预编译,这会扫描查找 classesN.dex 文件,并将它们编译成单个 .oat 文件,以供 Android 设备执行。因此,如果您的 minSdkVersion 为 21 或更高版本,系统会默认启用 MultiDex,并且您不需要 MultiDex 库。
经过网上的一番资料查询,得知是项目中android/app/build.gradle
文件中defaultConfig的minSdkVersion太低。
...
android {
...
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.baikeyang.blog"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
...
}
...
当找到项目中对应的位置,发现defaultConfig的minSdkVersion配置的是flutter.minSdkVersion的值,并没有直接写明minSdkVersion的值
那么问题来了,flutter.minSdkVersion这个对应的版本到底是多少呢?
继续查询一番,找到了flutter.minSdkVersion的版本信息。
前往自己的FlutterSDK目录中找到flutter.gradle文件:[盘符]:\[flutterSDK位置]\packages\flutter_tools\gradle\flutter.gradle
,在文件的36行就可以找到Flutter默认的minSdkVersion版本是多少,同时还可以知道compileSdkVersion、targetSdkVersion 分别是多少。
...
/** For apps only. Provides the flutter extension used in app/build.gradle. */
class FlutterExtension {
/** Sets the compileSdkVersion used by default in Flutter app projects. */
static int compileSdkVersion = 33
/** Sets the minSdkVersion used by default in Flutter app projects. */
static int minSdkVersion = 16
/** Sets the targetSdkVersion used by default in Flutter app projects. */
static int targetSdkVersion = 33
/**
* Sets the ndkVersion used by default in Flutter app projects.
* Chosen as default version of the AGP version below as found in
* https://developer.android.com/studio/projects/install-ndk#default-ndk-per-agp
*/
static String ndkVersion = "23.1.7779620"
/**
* Specifies the relative directory to the Flutter project directory.
* In an app project, this is ../.. since the app's build.gradle is under android/app.
*/
String source
/** Allows to override the target file. Otherwise, the target is lib/main.dart. */
String target
}
...
知道了minSdkVersion值是16。为了不影响FlutterSDK,我这里并没有直接在这里修改。而是返回项目中修改了项目中android/app/build.gradle
文件中defaultConfig的minSdkVersion
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.baikeyang.blog"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
重新编译运行项目,编译启动正常。