AB包基础
AB(AssetBundle)是一组被 Unity 按需打包的资源集合,重点是"按标签/目录划分、运行时按需加载"。生成后会得到:
AssetBundle Browser 导入方式
- 打开 Package Manager :Unity 顶部菜单选择
Window → Package Manager。 - Unity Registry 安装 :
- 将 Package source 设置为 Unity Registry;
- 在搜索框输入 AssetBundle Browser ,选择后点击 Install,等待自动集成完成。
- 若在官方仓库中不可用 :
- 在 Package Manager 左上角点击
+,选择 Add package from git URL...; - 输入
com.unity.assetbundlebrowser并点击 Add 完成安装。
- 在 Package Manager 左上角点击
- AB 包文件:真正的资源载体,按包名区分。
- Manifest 文件:为每个 AB 自动生成,记录资源清单、依赖关系、版本号、压缩信息等,加载时用它决定先加载谁、校验是否需要更新。
- 关键 AB 包:根清单(和输出目录同名的包),描述全部 AssetBundle 的拓扑,补充全局依赖信息。
AB包作用
- 降低首包体积:只把核心资源放进安装包,其余在线增量下载。
- 复用与热更新:按需更新单个包即可完成资源修复或新增内容。
- 精细化内存管理:结合
AssetBundle.Unload控制生命周期,避免一次性加载整套资源。 - 跨项目复用:可被多个项目/子游戏共享,只需统一 Manifest。
AB包打包
- 在工程中给资源配置 AssetBundle 标签,或用自定义 Builder 脚本按目录批量设置。
- 打开
BuildPipeline/Addressables 等构建入口,如官方示例工具窗口,选择 Build 选项卡。 - 设置参数(对应截图)后点击 Build:
- Build Target:输出目标平台,决定资源格式(示例为 Standalone Windows)。
- Output Path :生成目录(如
AssetBundles/PC)。 - Clear Folders:构建前清空输出目录,避免旧包残留。
- Copy to StreamingAssets :构建后自动复制到
StreamingAssets,这样在打包 Player 时 AssetBundle 会随应用一起进入安装包,运行时可通过Application.streamingAssetsPath直接定位,适合离线或首包必备资源。 - Compression :压缩模式,
Chunk Based Compression (LZ4)读写速度快、适合频繁加载,LZMA压缩率更高但解压慢。 - Exclude Type Information:若勾选会移除类型树信息,减少体积但会限制跨版本兼容性。
- Force Rebuild:忽略缓存,强制重新构建所有包,适合怀疑缓存损坏时使用。
- Ignore Type Tree Changes:即使类型树变化也复用增量缓存,可加快构建但可能导致运行时加载失败,除非对兼容性非常确定。
- Append Hash:在输出文件名后附加 Hash,可实现 CDN 缓存刷新、版本共存。
- Strict Mode:启用严格校验,发现未标记资源或依赖问题时会终止构建。
- Dry Run Build:只执行模拟构建,验证配置与依赖,不产生实际文件。
- 构建完成后,确认 manifest 与关键 AB 包齐全,将它们连同目标包上传或放入更新服务,运行时先加载关键 manifest,再按依赖加载具体 AB。
AB包资源加载
基础 API
csharp
// 加载 AB 包
AssetBundle bundle = AssetBundle.LoadFromFile("AB包路径/AB包名");
// 泛型方式加载资源
bundle.LoadAsset<T>("资源名");
// 指定类型加载资源
bundle.LoadAsset("资源名", typeof(GameObject));
// 同一个 AB 包不能重复加载,否则会报错
卸载
csharp
// 卸载单个包,true 表示连同实例一起卸载
bundle.Unload(true);
// 卸载所有已加载的 AB 包
AssetBundle.UnloadAllAssetBundles(true);
异步加载
csharp
StartCoroutine(LoadABRes("包名", "资源名"));
IEnumerator LoadABRes(string abName, string resName)
{
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync("包路径/包名");
yield return request;
GameObject prefab = request.assetBundle.LoadAsset<GameObject>(resName);
Instantiate(prefab);
}
AB包依赖关系
如果一个包中的资源和其他包的资源有依赖关系,那么只加载一个 AB 包无法正确加载资源,需要把依赖链上的所有包都加载出来。这时就要借助"主包"(根 manifest 包)获取依赖信息。
csharp
// 加载主包
AssetBundle mainBundle = AssetBundle.LoadFromFile("主包路径/主包名");
// 读取主包中的 manifest
AssetBundleManifest manifest = mainBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("ab包名");
foreach (string dependency in dependencies)
{
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + dependency);
}
下面是一个简单的AB包资源加载的管理器(伪代码)
csharp
// 由于 AB 包不能重复加载,用字典记录加载过的包
public Dictionary<string, AssetBundle> abDict = new Dictionary<string, AssetBundle>();
// 避免重复加载
public AssetBundle mainAB = null;
public AssetBundleManifest manifest = null;
public string Path => Application.streamingAssetsPath + "/";
public string Type
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
}
public Object LoadRes(string abName, string resName)
{
// 1. 加载主包
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(Path + Type);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
// 2. 加载依赖文件
string[] assetBundles = manifest.GetAllDependencies(abName);
for (int i = 0; i < assetBundles.Length; i++)
{
string dependencyName = assetBundles[i];
if (!abDict.ContainsKey(dependencyName))
{
AssetBundle dependencyBundle = AssetBundle.LoadFromFile(Path + dependencyName);
abDict.Add(dependencyName, dependencyBundle);
}
}
// 3. 加载所需包
if (!abDict.ContainsKey(abName))
{
AssetBundle targetBundle = AssetBundle.LoadFromFile(Path + abName);
abDict.Add(abName, targetBundle);
}
// 4. 加载所需资源
Object obj = abDict[abName].LoadAsset(resName);
if (obj is GameObject go)
{
return Instantiate(go);
}
{
return obj;
}
}