打新版本 APK 时,我遇到了一个问题:应用启动后黑屏,日志提示 Unity 找不到对应的 Java 方法。这个版本的 C# 和 Java 代码都没有修改,构建配置却有一处变化:Android Gradle Plugin(AGP)从 8.2.2 升级到了 8.6.0

排查后,我把问题定位到了 AGP 8.4 开始引入的库模块缩减行为变化。本文记录这个变化如何影响 Unity 导出工程,以及混淆规则应该放在哪里。

为什么没改代码,方法却找不到了?

这里升级的是 AGP 插件版本,要和 gradle-wrapper.properties 中的 Gradle 版本区分开。两者有关联,但不是同一个版本号。

AGP 8.4 发布说明提到:如果 Android 库子项目开启了代码缩减,提供给依赖它的应用模块的将是缩减后的类。

放到 Unity 导出工程中,可以这样理解:launcher 是应用模块,依赖 unityLibrary 库模块。如果 unityLibrary 开启了 minifyEnabled,它的代码就可能先被处理,再交给 launcher 打包。不能再依赖旧版本中应用模块拿到未缩减库代码的行为。

而我配置的混淆规则中,没有明确类名,而是使用* implements 进行匹配。因为 AGP 规则的修改,就导致我的规则不再生效了。

调整两个模块的混淆配置

对于这个 Unity 导出工程,我采用的方案是:关闭 unityLibrary 自身的缩减,由 launcher 在最终构建时统一处理,并让库模块提供需要保留的接口规则。

下面使用 Groovy DSL,展示需要合并到现有 build.gradle 中的配置。保留工程已有的 Unity、SDK 规则和其他构建设置,不要直接覆盖整个文件。

1. unityLibrary 提供保留规则

unityLibrary/build.gradle 中配置:

android {
defaultConfig {
consumerProguardFiles 'proguard-unity.txt', 'proguard-rules.pro'
}

buildTypes {
release {
minifyEnabled false
}
}
}

2. launcher 开启最终混淆

launcher/build.gradle 中配置:

android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
}
}
}

两个配置项的区别是:

配置项 作用
proguardFiles 当前模块执行缩减时使用的规则
consumerProguardFiles 库提供给使用方、在应用构建阶段生效的规则

为 Unity 调用的 Java 方法编写保留规则

假设自定义 Activity 的完整类名是 com.example.game.GameActivity,其中定义了一个供 Unity 调用的实例方法:

public class GameActivity extends com.unity3d.player.UnityPlayerActivity {
public void SetPlatformId() {
// 业务逻辑
}
}

那么,在 unityLibrary/proguard-rules.pro 中添加:

-keep class com.example.game.GameActivity {
public void SetPlatformId();
}

这是保留规则,不是 Java 类定义:需要写 -keep,方法声明以分号结束,不写方法体。这个示例保留目标类和指定方法,不会把该类的所有成员都列入保留范围。

使用时,把示例类名替换为工程中实际声明该方法的类名,并核对返回值、参数类型及是否为 static。例如实际签名是 SetPlatformId(int),就应写成:

-keep class com.example.game.GameActivity {
public void SetPlatformId(int);
}

用 Release 包验证

修改配置后,重新构建开启混淆的 Release 包进行测试。

这次排查给我的提醒是:跨语言调用不仅要关注保留了哪些接口,还要确认这些规则在哪个构建阶段生效。

升级构建工具后,即使业务代码没变,也需要重新验证开启混淆的正式包。