Android项目在发行版本中生成太多DEX文件

时间:2019-04-08 21:28:47

标签: android unity3d gradle dex

我正在研究一个从Unity导出为Android Studio项目的游戏。当我组装并作为调试版本运行时,它可以按预期工作。由于我们使用多个第三方库,因此有超过65K的方法,并且它会生成许多DEX文件(11个文件)。从这些DEX文件的内容来看,它们并不完整。实际上,它们中的大多数仅包含一个BuildConfig类或一堆相关的R类。实际上,只有两个DEX文件中有明显的内容,classes7.dex和classes11.dex。我不知道该应用程序如何运行;我认为主要活动需要在classes.dex中才能起作用。但是无论如何,实际上一切都很好。

但是,在发行版本中,情况要严重得多。我说的是109(一百零九!)DEX文件。出于某种原因,这似乎只是对11个DEX文件中最初包含的类进行了更细化的分离。在这里,事情开始崩溃。在启动时,ClassNotFoundExceptions开始出现在某些设备上,但在其他设备上运行良好。我所看到的表明它是否可以工作的常见因素是操作系统版本。所有设备都运行Android OS 5.0+,因此本机支持多义处理,但稳定的设备大多运行6.0 +。

主要活动是在classes54.dex中,它从classes30.dex中的类扩展而来,而class30.dex从class106.dex中的类扩展至Activity。这些类可以找到很好。例如,它抱怨找不到的第一个类在class91.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'
    }

}

3 个答案:

答案 0 :(得分:0)

如果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
....

如果使用“运行应用程序”按钮生成apk,则该apk可能包含许多dex文件。

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

答案 1 :(得分:0)

我发现了……并非最佳解决方案。我的应用目前的最低SDK目标是21岁以上。如果将其降低到20或更低,构建过程显然会改变。只有2个DEX文件出来。当然,这意味着我需要支持Android 4.4+而不是5.0 +。

要清楚,我所做的唯一更改是添加了行

minSdkVersion 20

targetSdkVersion 27上方,它将更改其构建方式。如果我将其更改为minSdkVersion 21或更高的数字,则表示它已损坏。

答案 2 :(得分:0)

使用Pre-dexing通常是大量dex文件的原因。

Pre-dexing是迭代项目所有模块并将其从Java字节码转换为Android字节码的过程。它将每个应用程序模块和每个依赖项构建为单独的DEX文件。使用此dexOption的目的在于以增量方式进行构建并加快构建过程,因为一个模块中的更改只会导致该模块的降级。

请尝试在build.gradle文件中使用以下dexOptions

android {
    ...
    dexOptions {
        preDexLibraries = false
    }
}

以上内容可以解决您的问题,并且您的应用程序不需要支持Android 4.4。

在定位minSdkVersion 21:https://android.googlesource.com/platform/art/+/lollipop-release/runtime/dex_file.cc#303时,似乎可以读取100个dex文件。这就是将您的api级别降级到20后您的应用程序运行正常的原因。