在Unity Addressables中,当Bundle Mode设为“Pack Together”时,若多个Group引用了同一资源(如共用材质、脚本ableObject或纹理),Addressables默认会将该资源**重复打包进每个依赖它的Bundle**,导致包体膨胀、加载冗余甚至AB引用不一致。典型表现为:相同Asset在不同Bundle中出现多份Hash,Build Report中显示高重复率,且运行时LoadAsset可能出现意外交互(如修改一个实例影响另一处)。此问题并非Bug,而是Pack Together模式下“按Group独立打包”的设计使然——它不自动做跨Group的资源去重。常见诱因包括未合理规划Group边界、误将共享资源放入多个可变Group、或未启用Content Packing Groups的依赖分析。解决核心在于**打破“隐式重复依赖”**,而非简单切换模式。需结合Group划分策略、Label管理与构建配置协同优化。
1条回答 默认 最新
三月Moon 2026-03-01 08:54关注```html一、现象层:识别重复打包的典型征兆
- Build Report 中显示同一 Asset(如
UI/DefaultMaterial.mat)在多个 Bundle 中出现,且各自拥有不同 Hash 值; - Addressables Analyze → “Find Duplicated Assets” 工具报告高重复率(>15%);
- 运行时调用
Addressables.LoadAssetAsync<Material>("UI/DefaultMaterial")返回不同实例,但修改其属性后,其他界面材质同步变化(说明实际是同一对象被多次加载而非克隆); - Profiler 中观察到相同纹理资源被多次解压、上传 GPU,
Texture2D.LoadImage调用频次异常升高; - Android APK / iOS IPA 解包后,
assets/bin/Data/StreamingAssets/aa/下多个 .bundle 文件均包含shared_icon_atlas.texture2d的完整二进制副本。
二、机制层:Pack Together 模式的设计本质与约束
Addressables 在 Pack Together 模式下执行的是Group 粒度的封闭式打包:每个 Group 独立构建其依赖图谱,不跨 Group 进行资源归属仲裁。其行为由以下核心规则驱动:
规则维度 表现 影响 依赖解析范围 仅扫描本 Group 内所有标记 Asset 及其显式/隐式引用链 共享资源若未被任一 Group 显式声明为“Owner”,则每个引用 Group 均视为独立 Owner Bundle 切分时机 在 BuildPipeline 完成后,按 Group 分别执行 ContentPacker.Pack()无全局去重阶段, ContentPackingGroup的IncludeInBuild若未启用,依赖分析即失效三、归因层:三大隐式重复依赖根源
- Group 边界污染:将
Common/目录下的材质、ScriptableObject 放入SceneA_Group和SceneB_Group两个可变 Group,而非统一归入Shared_Assets不变 Group; - Label 误用导致依赖泄露:为某 UI Prefab 打上
ui_loginLabel,其引用的BaseButton.cs脚本又间接引用ThemeSettings.asset,而该 ScriptableObject 未打任何 Label,Addressables 自动将其纳入所有引用它的 Group; - Content Packing Groups 配置缺失:未在
Edit → Project Settings → Addressable Assets → Build Settings中勾选Use Content Packing Groups,导致无法启用跨 Group 的依赖拓扑合并。
四、解法层:协同优化四步法
graph TD A[定义 Shared Group] --> B[启用 Content Packing Groups] B --> C[重构 Label 依赖链] C --> D[验证并固化构建策略] D --> E[CI/CD 中集成 Build Report 自检]关键操作示例:
// 1. 创建专用 Shared Group(Bundle Mode: Pack Together, Include In Build: true) // 并将所有跨场景复用资源拖入其中,设置 Label: shared_core // 2. 在 Addressables Groups 窗口右键 → 'Create Content Packing Group' // 命名为 'SharedPacking',勾选 'Include in Build',添加 Shared Group 为唯一来源 // 3. 移除所有非 Shared Group 中对 shared_core 资源的直接引用 // 改为通过 Addressables.LoadAssetAsync<T>(“res_name”) 动态加载五、验证层:构建后必检五项指标
- ✅ Build Report 中
Duplicated Assets Count≤ 3; - ✅ 同一 Asset 的
Bundle Name字段在 Report 中仅出现一次; - ✅ 运行时调用
Addressables.GetDownloadSizeAsync("shared_icon_atlas")返回值唯一且稳定; - ✅ Profiler → Memory → Texture2D 实例数 = 实际 Atlas 数量(非 Bundle 数量);
- ✅ 使用
Addressables.ResourceManager.GetResourceLocations("shared_icon_atlas")返回单个 Location。
六、进阶层:自动化防御体系构建
面向 5+ 年经验工程师,建议在项目中落地以下增强实践:
- 编写自定义 Editor Script,在每次 Build 前自动扫描所有 Group 中是否存在
Assets/Common/**/*路径资源的多 Group 引用; - 在 CI 流水线中集成 Python 脚本解析
BuildReport.json,当duplicate_ratio > 0.05时阻断发布; - 扩展 Addressables Analyze 模块,开发
FindCrossGroupDuplicates自定义分析器,可视化展示资源在 Group 间的传播路径; - 为团队制定《Addressables Group 划分黄金法则》文档,明确 “不变资源必须进入 Shared Group + Content Packing Group” 的强约束;
- 在 Addressables 初始化阶段注入
IResourceLocator实现,对重复加载的 shared asset 自动返回缓存实例(需配合Object.Instantiate防误改)。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- Build Report 中显示同一 Asset(如