我正在开发一个从Unity导出为Android Studio项目的游戏。当我组装并作为调试版本运行时,它按预期工作。由于我们使用多个第三方库,因此有超过65K的方法,它会生成相当多的DEX文件(11个文件)。查看这些DEX文件的内容,它们并不完整。实际上,它们中的大多数只包含一个BuildConfig类或一堆相关的R类。事实上,只有2个DEX文件中有任何可感知的内容,classes7.dex和classes11.dex。我不知道应用程序是如何运行的;我认为主要活动需要在classes.dex中才能工作。但无论如何一切都很好。
但是,在发布版本中,情况要糟糕得多。我在谈论109(一百零九个!)DEX文件。出于某种原因,这似乎只是对之前在11个DEX文件中的类进行更细粒度的分离。在这里,事情开始崩溃。在启动时,ClassNotFoundExceptions开始出现在某些设备上,但在其他设备上它可以正常工作。我看到的常见因素表明它是否有效是操作系统版本。所有设备都运行Android OS 5.0+,因此本机支持多索引,但稳定的设备大多运行6.0+。
主要活动在classes54.dex中,它从classes30.dex中的类扩展而来,该类从classes106.dex中的类扩展而来,该类从Activity扩展。那些可以找到的课程就好了。例如,它抱怨它找不到的第一个类在classes91.dex中已经结束了。
我认为问题是在gradle过程中,因为从Unity直接导出到APK或在Android Studio中构建时会出现问题。所以我的问题是如何:
从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_卖弄_德行.pro
-keep class android.support.multidex.** { *; }
# Those classes or methods used in the Application init
....
如果使用“运行应用程序”按钮生成apk,则apk可能包含许多dex文件。
使用“Build-> Make Module'app''或命令行。
我发现了......不太理想的解决方案。我的应用目前将目标定位为21+作为min SDK。如果我将其降低到20或更低,则构建过程显然会发生变化。只有2个DEX文件出来。当然这意味着我需要支持Android 4.4+而不是5.0+。
要清楚,我所做的唯一改变是添加线
minSdkVersion 20
在targetSdkVersion 27
之上,它改变了它的构建方式。如果我将它更改为minSdkVersion 21
或任何更高的数字,它会再次被打破。
使用Pre-dexing通常是大量dex文件的原因。
Pre-dexing是迭代所有项目模块并将它们从Java字节码转换为Android字节码的过程。它将每个app模块和每个依赖项构建为一个单独的DEX文件。这个dexOption用于以增量方式构建并加速构建过程,因为一个模块中的更改仅导致该模块的dexing。
请尝试在build.gradle文件中使用以下dexOptions
android {
...
dexOptions {
preDexLibraries = false
}
}
以上内容可以解决您的问题,您不需要为您的应用程序支持Android 4.4。
看起来在定位minSdkVersion 21时可以读取100个dex文件的限制:https://android.googlesource.com/platform/art/+/lollipop-release/runtime/dex_file.cc#303。这就是你的应用程序在将api级别降级到20之后正常工作的原因。