使用Custom Main Gradle减少DEX 64K
解读
在国内 Unity 项目上线 Android 渠道时,DEX 64K 方法数限制是必现痛点:当应用+引擎+第三方 SDK 的方法数超过 65536,打包直接失败。Unity 2019 以后官方把主 Gradle 模板暴露出来,允许开发者用 Custom Main Gradle Template(Assets/Plugins/Android/mainTemplate.gradle)直接干预最终合并的 build.gradle,从而按需裁剪、延迟加载、分包(multidex)或启用 R8/ProGuard,把方法数压到安全线以下,而不必等出包后再手动改 Android Studio 工程。面试官问“怎么用 Custom Main Gradle 减少 DEX 64K”,核心是想确认两点:
- 你是否真的理解 DEX 64K 的根因(方法数≠字节数,而是 Dalvik 64K 引用槽位);
- 能否在 Unity 侧闭环解决,而不是把锅甩给 Android 同事。
知识点
- 64K 触发条件:
dx打包时所有 classes*.dex 索引总和 ≥ 65536;- 国内渠道普遍要求 minSdkVersion ≤ 20,不能默认 multidex,必须手动开启。
- Custom Main Gradle Template 生效路径:
- Unity 出 Gradle 工程时,把
mainTemplate.gradle直接复制为launcher/build.gradle; - 与
baseProjectTemplate.gradle、launcherTemplate.gradle、gradleTemplate.properties共同构成最终构建脚本。
- Unity 出 Gradle 工程时,把
- 关键 DSL:
multidexEnabled trueimplementation 'androidx.multidex:multidex:2.0.1'proguardFiles,minifyEnabled,shrinkResourcespackagingOptions剔除多余.so与重复 META-INF
- Unity 侧辅助:
- Player Settings → Publishing Settings → Custom Main Gradle Template 勾选;
- Player Settings → Target Architecture 只保留 arm64,可瞬间砍掉 30% 方法数;
- Managed Stripping Level 选 Medium 或 High,配合
link.xml保留反射类; - 使用 R8(Gradle 6+ 默认)而非 ProGuard,压缩率提升 10~15%。
- 国内渠道特殊坑:
- 华为、OPPO 安全扫描不允许
multidex带legacy版本,必须androidx.multidex; - 部分 SDK(推送、支付)自带
android.support旧库,需exclude module防止重复合并; - 若接 抖音 SDK,其
bytecode插桩会膨胀方法数,需要pickFirsts强制去重。
- 华为、OPPO 安全扫描不允许
答案
- 在 Unity Editor 中勾选 Player Settings → Publishing Settings → Custom Main Gradle Template,生成
Assets/Plugins/Android/mainTemplate.gradle。 - 打开模板,在
android节点内增加:defaultConfig { minSdkVersion **19** // 国内渠道最低 targetSdkVersion **33** multiDexEnabled **true** // 关键开关 } - dependencies 区块追加:
implementation 'androidx.multidex:multidex:2.0.1' - 启用 R8 压缩:
并在buildTypes { release { minifyEnabled **true** shrinkResources **true** proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-unity.txt', 'proguard-user.txt' } }Assets/Plugins/Android新建proguard-user.txt,把 Unity 反射类、热更 DLL、第三方 SDK 的 keep 规则写全,防止运行时 ClassNotFound。 - 裁剪架构:
ndk { abiFilters 'arm64-v8a' // 仅保留 64 位,so 方法数大幅下降 } - 若方法数仍逼近 64K,则在
launcherTemplate.gradle中把dexOptions的preDexLibraries = false,强制 主 dex 最少化,并把 非启动路径的代码 通过multidex.keep文件延后到 secondary dex,确保冷启动主 dex 方法数 < 65536。 - 出包前用
Build Analyzer或dexcount-gradle-plugin扫描:
确认 release 主 dex 方法数 < 60K,留 5K 冗余给渠道二次加固插桩。./gradlew assembleRelease -PcountDexMethods
通过以上步骤,可在 Unity 侧闭环完成 DEX 64K 治理,无需出包后再回 Android Studio 补救,符合国内快节奏发版要求。
拓展思考
- Root-DEX 与 Secondary-DEX 加载时机:
国内加固厂商(腾讯乐固、网易易盾)会在attachBaseContext后重新注入 multidex,若 Unity 的Application继承关系写死,容易 NoClassDefFoundError。最佳实践是 自定义 Application 继承 MultiDexApplication,并在onCreate最前端初始化热更框架,保证次级 dex 加载完成后再反射 Unity 主 Activity。 - Instant Run 与 D8 冲突:
部分 CI 仍用旧 Gradle 4.x,开启 Instant Run 会导致dx与d8混合编译,方法数统计失真。升级 Gradle 7+ 并关闭 Instant Run,可让 R8 全量优化,方法数再降 5~8%。 - Unity 2022 LTS 的新方案:
Unity 2022.3 开始支持 Assembly Definition Reference + Build-time code stripping,可把巨量引擎模块(UI、Tilemap、Analytics)在导出 Gradle 前就裁剪掉,主 dex 方法数直接减半;但国内老项目多数基于 2019 LTS,需要评估升级成本。 - 数字孪生/仿真场景:
若项目非游戏而是 数字孪生,往往集成 GIS、CAD、BIM 解析库,方法数爆炸更猛。此时可在mainTemplate.gradle里用 productFlavors 做 拆分 APK:phoneflavor 只保留核心可视化,方法数 < 50K;padflavor 打开全量模块,强制 multidex;
通过 Unity Cloud Build 自动打双包,兼顾 华为应用商店 与 私有部署 两种场景。