AssetBundle特性
1. AB包可以存储绝大部分Unity资源但无法直接存储C#脚本,所以代码的热更新需要使用Lua或者存储编译后的DLL文件,还有HybridCLR热更新插件,代码资源都可以热更。
2. AB包不能重复进行加载,当AB包已经加载进内存后必须卸载后才能重新加载。
3. 多个资源分布在不同的AB包可能会出现一个预制体的贴图等部分资源不在同一个包下,直接加载会出现部分资源丢失的情况,即AB包之间是存在依赖关系的,在加载当前AB包时需要一并加载其所依赖的包。
4. 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)
插件概述
下载地址:https://github.com/Unity-Technologies/AssetBundles-Browser
1. Configure面板 :能查看当前AB包及其内部资源的基本情况(大小,资源,依赖情况等),也是配置在Build时,打包的那些ab包
2. Build面板:负责AssetBundle打包的相关设置 按Build即可进行打包
2.1 三种压缩方式
1. NoCompression:不压缩,解压快,包较大,不建议使用。
2. LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
3. LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,更建议使用。
一般需要进行更改的设置即为图中勾选的相关选项设置。
3. Inspect面板:主要用来查看已经打包后的AB包文件的一些详细情况(大小,资源路径等)
加载相关API
//AB包加载所需相关API
//1. 根据路径进行加载AB包 注意AB包不能重复加载
AssetBundle ab = AssetBundle.LoadFromFile(path);
//2. 加载ab包下指定名称和类型的资源
T obj = ab.LoadAsset<T>(ResourceName); //泛型加载
Object obj = ab.LoadAsset(ResourceName); //非泛型加载 后续使用时需强转类型
Object obj = ab.LoadAsset(ResourceName,Type); //参数指明资源类型 防止重名
T obj = ab.LoadAssetAsync<T>(resName); //异步泛型加载
Object obj = ab.LoadAssetAsync(resName); //异步非泛型加载
Object obj = ab.LoadAssetAsync(resName,Type); //参数指明资源类型 防止重名
//3. 卸载ab包 bool参数代表是否一并删除已经从此AB包中加载进场景的资源(一般为false)
ab.UnLoad(false); //卸载单个ab包
AssetBundle.UnloadAllAssetBundles(false); //卸载所有AB包
示例代码:
using System;
using System.Net.Mime;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Common
{
/// <summary>
/// AB包管理器 全局唯一 使用单例模式
/// </summary>
public class ABManager : MonoSingleton<ABManager>
{
//AB包缓存---解决AB包无法重复加载的问题 也有利于提高效率。
private Dictionary<string, AssetBundle> abCache;
private AssetBundle mainAB = null; //主包
private AssetBundleManifest mainManifest = null; //主包中配置文件---用以获取依赖包
//各个平台下的基础路径 --- 利用宏判断当前平台下的streamingAssets路径
private string basePath { get
{
//使用StreamingAssets路径注意AB包打包时 勾选copy to streamingAssets
#if UNITY_EDITOR || UNITY_STANDALONE
return Application.dataPath + "/StreamingAssets/";
#elif UNITY_IPHONE
return Application.dataPath + "/Raw/";
#elif UNITY_ANDROID
return Application.dataPath + "!/assets/";
#endif
}
}
//各个平台下的主包名称 --- 用以加载主包获取依赖信息
private string mainABName
{
get
{
#if UNITY_EDITOR || UNITY_STANDALONE
return "StandaloneWindows";
#elif UNITY_IPHONE
return "IOS";
#elif UNITY_ANDROID
return "Android";
#endif
}
}
//继承了单例模式提供的初始化函数
protected override void Init()
{
base.Init();
//初始化字典
abCache = new Dictionary<string, AssetBundle>();
}
//加载AB包
private AssetBundle LoadABPackage(string abName)
{
AssetBundle ab;
//加载ab包,需一并加载其依赖包。
if (mainAB == null)
{
//根据各个平台下的基础路径和主包名加载主包
mainAB = AssetBundle.LoadFromFile(basePath + mainABName);
//获取主包下的AssetBundleManifest资源文件(存有依赖信息)
mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
//根据manifest获取所有依赖包的名称 固定API
string[] dependencies = mainManifest.GetAllDependencies(abName);
//循环加载所有依赖包
for (int i = 0; i < dependencies.Length; i++)
{
//如果不在缓存则加入
if (!abCache.ContainsKey(dependencies[i]))
{
//根据依赖包名称进行加载
ab = AssetBundle.LoadFromFile(basePath + dependencies[i]);
//注意添加进缓存 防止重复加载AB包
abCache.Add(dependencies[i], ab);
}
}
//加载目标包 -- 同理注意缓存问题
if (abCache.ContainsKey(abName)) return abCache[abName];
else
{
ab = AssetBundle.LoadFromFile(basePath + abName);
abCache.Add(abName, ab);
return ab;
}
}
//==================三种资源同步加载方式==================
//提供多种调用方式 便于其它语言的调用(Lua对泛型支持不好)
#region 同步加载的三个重载
/// <summary>
/// 同步加载资源---泛型加载 简单直观 无需显示转换
/// </summary>
/// <param name="abName">ab包的名称</param>
/// <param name="resName">资源名称</param>
public T LoadResource<T>(string abName,string resName)where T:Object
{
//加载目标包
AssetBundle ab = LoadABPackage(abName);
//返回资源
return ab.LoadAsset<T>(resName);
}
//不指定类型 有重名情况下不建议使用 使用时需显示转换类型
public Object LoadResource(string abName,string resName)
{
//加载目标包
AssetBundle ab = LoadABPackage(abName);
//返回资源
return ab.LoadAsset(resName);
}
//利用参数传递类型,适合对泛型不支持的语言调用,使用时需强转类型
public Object LoadResource(string abName, string resName,System.Type type)
{
//加载目标包
AssetBundle ab = LoadABPackage(abName);
//返回资源
return ab.LoadAsset(resName,type);
}
#endregion
//================三种资源异步加载方式======================
/// <summary>
/// 提供异步加载----注意 这里加载AB包是同步加载,只是加载资源是异步
/// </summary>
/// <param name="abName">ab包名称</param>
/// <param name="resName">资源名称</param>
public void LoadResourceAsync(string abName,string resName, System.Action<Object> finishLoadObjectHandler)
{
AssetBundle ab = LoadABPackage(abName);
//开启协程 提供资源加载成功后的委托
StartCoroutine(LoadRes(ab,resName,finishLoadObjectHandler));
}
private IEnumerator LoadRes(AssetBundle ab,string resName, System.Action<Object> finishLoadObjectHandler)
{
if (ab == null) yield break;
//异步加载资源API
AssetBundleRequest abr = ab.LoadAssetAsync(resName);
yield return abr;
//委托调用处理逻辑
finishLoadObjectHandler(abr.asset);
}
//根据Type异步加载资源
public void LoadResourceAsync(string abName, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler)
{
AssetBundle ab = LoadABPackage(abName);
StartCoroutine(LoadRes(ab, resName,type, finishLoadObjectHandler));
}
private IEnumerator LoadRes(AssetBundle ab, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler)
{
if (ab == null) yield break;
AssetBundleRequest abr = ab.LoadAssetAsync(resName,type);
yield return abr;
//委托调用处理逻辑
finishLoadObjectHandler(abr.asset);
}
//泛型加载
public void LoadResourceAsync<T>(string abName, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object
{
AssetBundle ab = LoadABPackage(abName);
StartCoroutine(LoadRes<T>(ab, resName, finishLoadObjectHandler));
}
private IEnumerator LoadRes<T>(AssetBundle ab, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object
{
if (ab == null) yield break;
AssetBundleRequest abr = ab.LoadAssetAsync<T>(resName);
yield return abr;
//委托调用处理逻辑
finishLoadObjectHandler(abr.asset as T);
}
//====================AB包的两种卸载方式=================
//单个包卸载
public void UnLoad(string abName)
{
if(abCache.ContainsKey(abName))
{
abCache[abName].Unload(false);
//注意缓存需一并移除
abCache.Remove(abName);
}
}
//所有包卸载
public void UnLoadAll()
{
AssetBundle.UnloadAllAssetBundles(false);
//注意清空缓存
abCache.Clear();
mainAB = null;
mainManifest = null;
}
}
}