欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法

程序员文章站 2022-07-15 10:18:54
...

一、问题

Unity打包apk时报了如下的错

D8: Cannot fit requested classes in a single dex file (# methods: 73376 > 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

Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法

二、原因

Android 5.0之前的版本(API level < 21)使用Dalvik runtime来执行代码,默认限制每个APK只能使用一个classes.dex文件,而DEX规范又将单个DEX文件内引用的方法总数限制为65536个,所以如果游戏中使用了较多的第三方SDK,很容易就会超过这个限制。

三、测试,生成超过65535个函数

如果你工程中没有这么多java函数,可以自己写个python脚本生成超过65535个函数,例:

import random
import os

letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

func_tamplate='''
    public void FUNC_NAME()
    {
        Log.d("LOG_TEST", "FUNC_NAME");
    }

'''

def rand_name():
    letter_cnt = random.randint(8,20)
    func_name = ''
    for letter_cnt in range(letter_cnt):
        func_name += random.choice(letters)
    return func_name

def gen_func():
    return func_tamplate.replace('FUNC_NAME', rand_name())

def gen_java_class_file():
    java_file_txt='''
package com.linxinfa.javatest;
import android.util.Log;

public class CLASS_NAME 
{
    FUNC_TEXT
}
'''
    
    funcs = ''
    # 一个java文件含7000个方法
    for i in range(7000):
        funcs += gen_func()
    class_name = rand_name()
    java_file_txt = java_file_txt.replace('CLASS_NAME', class_name)
    java_file_txt = java_file_txt.replace('FUNC_TEXT', funcs)
    with open(class_name + '.java', 'w') as f:
        f.write(java_file_txt)

if '__main__' == __name__:
    # 生成10个java文件,一个java文件含7000个方法,这样就超过65535个方法了
    for i in range(10):
        gen_java_class_file() 

四、解决办法

办法1:在Player Settings中将支持的最低Android API级别设定为21及以上。Android API Level 21及更高版本支持从APK文件中加载多个DEX文件,因此不会受64K的限制。

办法2:使用Custom Gradle配置文件并启用MultiDex支持(在PlayerSettings > Publish Settings > Build设置中勾选Custom Launcher Gradle Template,然后修改项目目录Assets/Plugins/Android/launcherTemplate.gradle启用MultiDex支持)

办法3:修改Unity Editor默认的Gradle配置文件并启用MultiDex支持(Unity安装目录/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle

本文介绍方法2的做法。

1、勾选Custom Gradle Template

PlayerSettings > Publish Settings > Build设置中勾选Custom Launcher Gradle Template
Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法

此时Assets/Plugins/Android/目录中会自动创建一个launcherTemplate.gradle文件
Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法

3、添加multiDexEnabled true

打开launcherTemplate.gradle,在defaultConfig配置块中,增加multiDexEnabled true

android {
        defaultConfig {
            ...
            multiDexEnabled true
            ...
        }
        ...
    }

4、添加multidex依赖

如果你的项目没有使用AndroidX

dependencies {
      implementation 'com.android.support:multidex:1.0.3'
}

如果项目使用了AndroidX,那么添加下面的支持库依赖项

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

如下,是我的mainTemplate.gradle

// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN

apply plugin: 'com.android.application'

dependencies {
    implementation project(':unityLibrary')
	implementation 'com.android.support:multidex:1.0.3'
    }

android {
    compileSdkVersion **APIVERSION**
    buildToolsVersion '**BUILDTOOLS**'

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    defaultConfig {
		multiDexEnabled true
        minSdkVersion **MINSDKVERSION**
        targetSdkVersion **TARGETSDKVERSION**
        applicationId '**APPLICATIONID**'
        ndk {
            abiFilters **ABIFILTERS**
        }
        versionCode **VERSIONCODE**
        versionName '**VERSIONNAME**'
    }

    aaptOptions {
        noCompress = ['.unity3d', '.ress', '.resource', '.obb'**STREAMING_ASSETS**]
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
    }**SIGN**

    lintOptions {
        abortOnError false
    }

    buildTypes {
        debug {
            minifyEnabled **MINIFY_DEBUG**
            proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG**
            jniDebuggable true
        }
        release {
            minifyEnabled **MINIFY_RELEASE**
            proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG**
        }
    }**PACKAGING_OPTIONS****SPLITS**
**BUILT_APK_LOCATION**
    bundle {
        language {
            enableSplit = false
        }
        density {
            enableSplit = false
        }
        abi {
            enableSplit = true
        }
    }
}**SPLITS_VERSION_CODE****LAUNCHER_SOURCE_BUILD_SETUP**

5、修改AndroidManifest.xml

修改位于项目目录Asset/Plugins/Android/AndroidManifest.xml文件,给application添加MultiDexApplication

android:name="android.support.multidex.MultiDexApplication"

如下
Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法

6、Application类,继承MultiDexApplication

如果你没有自己实现Application类,则跳过此步。

public class MyApplication extends MultiDexApplication { ... }

五、打包测试

打包apk,解压后,可以看到有多个dex
Unity打包apk报错: Cannot fit requested classes in a single dex file (# methods: 73376 > 65536)的解决办法