Android 项目在发布版本中生成过多的 DEX 文件

标签 android unity3d gradle dex

我正在开发一款从 Unity 作为 Android Studio 项目导出的游戏。当我组装并作为调试版本运行时,它按预期工作。由于我们使用了多个 3rd 方库,有超过 65K 种方法,并且它生成了相当多的 DEX 文件(11 个文件)。查看这些DEX文件的内容,并不都是全的。事实上,它们中的大多数只包含一个 BuildConfig 类,或者一堆相关的 R 类。事实上,只有 2 个 DEX 文件中有任何值得注意的内容,即 classes7.dex 和 classes11.dex。我什至不知道该应用程序是如何运行的;我认为主要 Activity 需要在 classes.dex 中才能工作。但无论如何,实际上一切正常。

然而,在发布版本中,情况要糟糕得多。我说的是 109(一百零九个!)DEX 文件。由于某种原因,这似乎只是对最初在 11 个 DEX 文件中的类进行了更精细的分离。在这里,事情开始崩溃。启动时,ClassNotFoundExceptions 开始出现在一些 设备上,但在其他设备上运行良好。我所看到的表明它是否有效的共同因素是操作系统版本。所有设备都运行 Android OS 5.0+,因此原生支持多索引,但稳定的设备大多运行 6.0+。

主要的activity在classes54.dex中,classes30.dex中扩展了一个类,classes30.dex中扩展了class106.dex中的一个类,classes106.dex中扩展了Activity。它可以找到的那些类虽然很好。例如,它提示找不到的第一个类在 classes91.dex 中结束。

我认为问题出在 gradle 进程中,因为从 Unity 直接导出到 APK 或在 Android Studio 中构建时会出现问题。所以我的问题是我该怎么做:

  1. 说服 Unity/Android Studio/Gradle 输出合理数量的 DEX 文件,或者
  2. 让所有设备在查找类时查看所有 dex 文件,即使有 100 多个?

从 Unity 导出时创建的当前 build.gradle:

buildscript {
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

allprojects {
    repositories {
        flatDir {
            dirs 'libs'
        }
        google()
    }
}

apply plugin: 'com.android.application'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation(name: 'GoogleAIDL', ext:'aar')
    implementation(name: 'GooglePlay', ext:'aar')
    implementation(name: 'android.arch.lifecycle.runtime-1.0.0', ext:'aar')
    //...
    //Also included: Google Play, Facebook, Crashlytics, AdMob, Firebase, and more, redacted for convenience
    //...
    implementation project(':Firebase')
    implementation project(':GoogleMobileAdsIronSourceMediation')
    implementation project(':GoogleMobileAdsMediationTestSuite')
    implementation project(':GoogleMobileAdsPlugin')
    implementation project(':GoogleMobileAdsTapjoyMediation')
    implementation project(':GooglePlayGamesManifest.plugin')
    implementation project(':unity-android-resources')
}

android {
    compileSdkVersion 27
    buildToolsVersion '28.0.3'

    defaultConfig {
        targetSdkVersion 27
        applicationId 'redacted'
        multiDexEnabled true
        ndk {
            abiFilters 'armeabi-v7a'
        }
        versionCode 0
        versionName '1.0.8'
    }

    dexOptions {
        incremental true
            javaMaxHeapSize "4g"
    }    

    lintOptions {
        abortOnError false
    }

    aaptOptions {
        noCompress '.unity3d', '.ress', '.resource', '.obb', 'crashlytics-build.properties', 'google-services-desktop.json', 'someotherfiles'
    }

    signingConfigs {
        release {
            storeFile file('/path/to/key.keystore')
            storePassword 'redacted'
            keyAlias 'key'
            keyPassword 'redacted'
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
            useProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'
            jniDebuggable true
            //Explicitly sign with release key anyway
            signingConfig signingConfigs.release
        }
        release {
            minifyEnabled false
            useProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'
            signingConfig signingConfigs.release
        }
    }

    packagingOptions {
        doNotStrip '*/armeabi-v7a/*.so'
    }

}

最佳答案

当minSdkVersion小于21时使用multiDex,需要配置multiDexKeepProguard。

链接https://developer.android.com/studio/build/multidex#keep

像这样

...
multiDexEnabled true
multiDexKeepProguard file("keep_in_main_dex.pro")
...

keep_in_main_dex.pro

-keep class android.support.multidex.** { *; }
# Those classes or methods used in the Application init
....

如果使用“Run app”按钮生成apk,apk可能包含很多dex文件。

使用“Build->Make Module 'app'”或命令行。

关于Android 项目在发布版本中生成过多的 DEX 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55582030/

相关文章:

java - 如何在 Firebase 实时数据库中将记录从一个位置复制到另一个位置?

android - 如何使用 StaggeredLayoutManager 实现无限滚动

c# - Unity中的LoadScene()函数什么时候改变场景?

java - 来自 aws-java-sdk 的 DynamoDB 在 gradle 下不完整

android - 如何判断 LAST PictureListener.onNewPicture() 调用?

android - java.lang.IllegalArgumentException : register too many Broadcast Receivers

unity3d - 无法将 Visual Studio for Mac 调试器附加到 Unity 2020

c# - 如何在unity中绘制多笔划线

android - android studio 3.4.2 gradle项目同步失败错误,无法解决依赖关系错误?

gradle - 如何为 logback-redis-appender 指定 redis 客户端依赖