内容提要
AGP 从 8.2.2 升级到 8.6.0 后,Unity 应用启动黑屏,日志提示找不到 Java 方法。原因是 AGP 8.4 起,若 unityLibrary 库模块开启代码缩减,会先输出缩减后的类,导致 launcher 中基于 * implements 的混淆规则失效。解决方案:关闭 unityLibrary 自身缩减,由 launcher 统一混淆,库模块通过 consumerProguardFiles 提供保留规则,并用 -keep 明确保留 Unity 调用的方法。
延伸解读
AGP 版本与 Gradle 版本的区别
文章特别提醒,AGP 插件版本与 gradle-wrapper.properties 中的 Gradle 版本是两回事,两者有关联但版本号不同。升级 AGP 时,不要误以为 Gradle 版本也同步升级,排查构建问题时应分别确认这两个版本,避免混淆问题根源。
库模块缩减行为变化的影响
AGP 8.4 起,若 Android 库子项目开启代码缩减,提供给应用模块的将是缩减后的类。在 Unity 导出工程中,若 unityLibrary 开启 minifyEnabled,其代码可能先被处理再交给 launcher 打包,导致 launcher 中基于 * implements 的混淆规则失效,进而出现找不到 Java 方法的问题。
混淆规则应放在哪个构建阶段
文章强调,跨语言调用不仅要关注保留了哪些接口,还要确认规则在哪个构建阶段生效。proguardFiles 用于当前模块执行缩减时的规则,consumerProguardFiles 则是库提供给使用方、在应用构建阶段生效的规则。关闭 unityLibrary 自身缩减、由 launcher 统一混淆,并让库模块通过 consumerProguardFiles 提供保留规则,是解决该问题的关键。
为 Unity 调用的方法编写精确保留规则
保留规则不是 Java 类定义,需要写 -keep,方法声明以分号结束,不写方法体。示例中只保留目标类和指定方法,不会保留该类的所有成员。使用时需替换为实际类名,并核对返回值、参数类型及是否为 static,例如 SetPlatformId(int) 应写成 -keep class com.example.game.GameActivity { public void SetPlatformId(int); }。
Q&A
为什么升级 AGP 后 Unity 应用启动黑屏,日志提示找不到 Java 方法?
因为 AGP 从 8.4 开始,如果 unityLibrary 库模块开启了代码缩减(minifyEnabled),它会先输出缩减后的类,导致 launcher 中基于 * implements 的混淆规则失效,从而 Unity 找不到对应的 Java 方法。
AGP 8.4 对库模块的代码缩减做了什么改变?
AGP 8.4 发布说明提到:如果 Android 库子项目开启了代码缩减,提供给依赖它的应用模块的将是缩减后的类。这意味着应用模块不能再依赖旧版本中拿到未缩减库代码的行为。
如何调整 unityLibrary 和 launcher 的混淆配置来解决这个问题?
关闭 unityLibrary 自身的缩减,由 launcher 在最终构建时统一处理,并让库模块提供需要保留的接口规则。具体配置:在 unityLibrary/build.gradle 中设置 minifyEnabled false 并配置 consumerProguardFiles;在 launcher/build.gradle 中设置 minifyEnabled true 并配置 proguardFiles。
proguardFiles 和 consumerProguardFiles 有什么区别?
proguardFiles 是当前模块执行缩减时使用的规则;consumerProguardFiles 是库提供给使用方、在应用构建阶段生效的规则。
如何为 Unity 调用的 Java 方法编写保留规则?
在 unityLibrary/proguard-rules.pro 中添加 -keep 规则,例如:-keep class com.example.game.GameActivity { public void SetPlatformId(); }。需要写 -keep,方法声明以分号结束,不写方法体。使用时替换为实际类名和方法签名。
修改混淆配置后如何验证?
重新构建开启混淆的 Release 包进行测试。升级构建工具后,即使业务代码没变,也需要重新验证开启混淆的正式包。