一句话
两个 SDK 各自带了同一个"零件",但版本不一样,游戏不知道该用哪个,于是编译失败或者运行时闪退。
一、什么是"依赖"?
SDK 不是从零写出来的,它内部也会用别人做好的工具包。比如:
- 联网用OkHttp
- 处理数据用Gson
- 谷歌相关功能用Google Play Services
这些被 SDK 用到的工具包,就叫依赖。
打个比方:你买了两台家电(SDK A 和 SDK B),每台都附带了一根电源线(依赖)。
二、冲突是怎么发生的?
你的游戏 ├── 广告 SDK → 自带 Gson 2.8 └── 统计 SDK → 自带 Gson 2.10游戏里同时出现两个 Gson,就会出现两种情况:
| 情况 | 比喻 | 表现 |
|---|---|---|
| 两份一模一样的东西 | 两根完全一样的电源线,插座只能插一根 | 打包失败,报Duplicate class |
| 只留了一份,但版本不对 | 留下的是旧电源线,新家电插不上 | 打包成功,但玩的时候闪退,报NoSuchMethodError或ClassNotFoundException |
第二种更麻烦,因为测试时不一定能发现,上线后才崩。
三、怎么看懂报错
遇到冲突时,报错信息里会直接写出是哪个零件。比如:
Duplicate class com.google.gson.Gson found in modules gson-2.8.6.jar gson-2.10.1.jar翻译成大白话:Gson 有两份,一份 2.8.6,一份 2.10.1。
常见报错速查:
| 报错关键词 | 意思 |
|---|---|
Duplicate class | 同一个零件有两份(Android) |
NoSuchMethodError/ClassNotFoundException | 零件版本不对,找不到需要的功能(Android) |
duplicate symbol | 同一个零件有两份(iOS) |
Program type already present | 和Duplicate class一样,老版本工具的说法 |
四、解决办法(从简单到复杂)
以下以Unity 打包安卓为例。
办法 1:删掉多余的那份文件
很多 SDK 是把.aar或.jar文件直接放进Assets/Plugins/Android/文件夹的。
打开这个文件夹看看,如果发现:
Assets/Plugins/Android/ ├── gson-2.8.6.jar ← 旧的 └── gson-2.10.1.jar ← 新的删掉旧的,留下新的,重新打包。
一般留新版本,因为新版本通常兼容旧版本的用法。删完一定要在手机上把相关功能都试一遍。
办法 2:用 EDM4U 统一管理(推荐)
手动删文件容易出错。Unity 上有个专门管依赖的免费工具:External Dependency Manager(简称 EDM4U)。大部分正规 SDK(Firebase、各大广告平台)都自带它。
它的作用就像一个管家:每个 SDK 告诉管家"我需要什么",管家统一去下载,同一个零件只下载一份,并自动选一个合适的版本。
每个 SDK 的需求写在一个 xml 文件里,放在任意Editor文件夹下,例如Assets/MySDK/Editor/MySDKDependencies.xml:
<dependencies><androidPackages><!-- 告诉管家:我需要 Gson 2.10.1 --><androidPackagespec="com.google.code.gson:gson:2.10.1"/></androidPackages></dependencies>然后在菜单里点:
Assets → External Dependency Manager → Android Resolver → Force Resolve管家会把所有 SDK 的需求汇总,自动处理重复的版本。
⚠️ 用了 EDM4U 之后,不要再手动往
Plugins/Android里拷同样的 jar/aar,否则又会重复。
办法 3:修改 Gradle 配置,强制指定版本
如果管家也搞不定,可以直接告诉打包工具"只用哪个版本"。
第一步:打开自定义配置文件
Edit → Project Settings → Player → 安卓图标 → Publishing Settings → 勾选 Custom Main Gradle Template项目里会出现Assets/Plugins/Android/mainTemplate.gradle。
第二步:在文件里加上下面这段
// 不管哪个 SDK 要什么版本,Gson 一律用 2.10.1configurations.all{resolutionStrategy{force'com.google.code.gson:gson:2.10.1'}}另一种写法:不让某个 SDK 带它自己的那份
dependencies{implementation('com.example:ad-sdk:1.0.0'){// 广告 SDK 别带 Gson 了,用别人的就行exclude group:'com.google.code.gson',module:'gson'}**DEPS**}
**DEPS**是 Unity 自带的占位符,不要删掉它。
办法 4:找 SDK 厂商
有些 SDK 把别人的零件直接打包进了自己的文件里,你删不掉、也排除不了。
这时只能联系厂商,问他们:
- 有没有新版本解决了这个问题?
- 能不能提供一个不内置这个零件的版本?
五、苹果手机(iOS)怎么办?
iOS 上的报错一般是:
duplicate symbol _xxxxx in: libSDK_A.a libSDK_B.a意思是两个 SDK 都内置了同一段代码。
解决思路和安卓一样:
- 优先使用 CocoaPods 版本的 SDK(EDM4U 会自动帮你管理),它会像管家一样只装一份;
- 尽量不要把
.a/.framework文件手动拖进项目; - 实在不行,找厂商要新版本。
在 xml 里写 iOS 需求的方式:
<dependencies><iosPods><iosPodname="GoogleUtilities"version="~> 7.0"/></iosPods></dependencies>六、怎么避免以后再遇到
| 习惯 | 说明 |
|---|---|
| 一次只接一个 SDK | 接完立刻打包测试,出了问题马上知道是谁引起的 |
| 优先选支持 EDM4U 的 SDK | 让管家管,比手动拷文件靠谱 |
| 不随手拷 jar/aar | 文件越乱,越容易重复 |
| 升级 SDK 后完整测一遍 | 版本冲突经常在升级后才出现 |
| 记下每个 SDK 的版本 | 出问题时方便回退 |
七、总结
- 是什么:两个 SDK 带了同一个零件的不同版本。
- 表现:打包失败(有两份),或者玩的时候闪退(版本不对)。
- 怎么查:看报错,里面会写出零件名字和版本。
- 怎么修:
- 删掉多余的旧文件;
- 用 EDM4U 统一管理;
- 在 Gradle 里强制指定版本或排除;
- 找厂商要新版本。
记住一句话:同一个零件,游戏里只能留一份,并且要选大家都能用的那个版本。