教程-【唐老狮】Unity热更新之AssetBundle
AB包理论基础 什么是AB包 特定于平台的资产压缩包,类似压缩文件
资产包括:模型、贴图、预设体、音效、材质球等
AB包的作用 相对于Resources下的资源AB包能更好管理资源,resources打包后是只读的,AB包存储位置可自定义,后期可以动态更新
减小包体大小:压缩资源、减少初始包大小
热更新:资源热更新、脚本热更新
AB包资源打包 1.unity编辑器开发,自定义打包工具 如果想自己写打包工具,学这个
2.官方提供好的打包工具 AssetBundleBrowser
//现在(2023-4)建议使用addressable
解压方式:
LZMA:压缩后文件小,使用其中任何资源都要解压整个包
LZ4:压缩后文件稍大,使用其中某个资源只需打包该资源
AB包资源加载
1 2 3 4 5 6 7 var ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"某个路径" );var obj1 = ab.LoadAsset<资源类型>("资源名" );var obj2 = ab.LoadAsset("资源名" ,typepf(资源类型))as 资源类型
1 2 3 4 5 6 7 8 IEnumerator LoadABRes (string ABName, string resName ) { AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetPath +"某个路径" ); var abq = abcr.assetBudle.LoadassetAsync("资源名" ,typeof (类型)); yield return abq; }
1 StartCoroutine(LoadABRes("包名" ,"资源名" ));
1 AssetBundle.UnloadAllAssetBundles(false );
AB包依赖 在包中的A资源如果使用了另外一个B资源(A依赖B),会自动的将它打包到同一个包中。
如果A资源和B资源打包到了不同的包中,只加载A资源所在的包,会出现B资源丢失。此时B资源所在的包叫依赖包,需要加载依赖包使A资源正常使用
1 2 3 4 5 6 7 8 9 10 11 12 var ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath +"某个路径A" )AssetBundle abMain = AssetBundle. LoadFromFile(Application.streamingAssetsPath+"主包路径" ); AssetBundleMainfest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest" ); string [] strs = abMainifest.GetAllDependencies("路径A的包名" );for (int i =0 ;i<strs.Length;i++){ AssetBundle.LoadFromFile(Application.streamingAssetsPath +"/" +strs[i]); }
AB包资源管理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 public class ABMgr : SingletonMono <ABMgr >{ private Dictionary<string ,AssetBundle> abDic = new (); private string PathUrl => Application.streamingAssetsPath + "/" ; private string MainABName { get { #if UNITY_IOS return "IOS" ; #elif UNITY_ANDROID return "ANDROID" ; #else return "PC" ; } } private AssetBundle mainAB = null ; private AssetBundleManifest manifest = null ; public object LoadRes (string abName,string resName ) { LoadAB(abName); return abDic[abName].LoadAsset(resName); } public object LoadRes (string abName,string resName, System.Type type ) { LoadAB(abName); return abDic[abName].LoadAsset(resName,type); } public object LoadRes <T >(string abName,string resName ) where T:object { LoadAB(abName); return abDic[abName].LoadAsset<T>(resName); } public void LoadAB (string name ) { if (maniAB = null ) { mainAB = AssetBundle.LoadFromFile(PathUrl+MainABName); manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest" ); } AssetBundle ab = null ; string [] strs = manifest.GetAllDependencies(abName); for (int i = 0 ; i<strs.Length;i++) { if (!abDic.ContainsKey(strs[i])) { ab = AssetBundle.LoadFromFile(PathUrl + strs[i]); abDic.Add(str[i],ab); } } if (!abdic.ContainsKey(abName)) { ab = AssetBunle.LoadFromFile(PathUrl + abName); abDic.Add(Abname,ab); } } public void LoadResAsync (string abName,string resName,UnityAction<Object> callBack ) { StartCoroutine(ReallyLoadResAsync(abName,resName,callBack)); } private IEnumerator ReallyLoadResAsync (string abName,string resName,UnityAction<Object> callBack ) { LoadAB(abName); var abr = abDic[abName].LoadAssetAsync(resName); yield return abr; callBack(abr.asset); } public void LoadResAsync (string abName,string resName,System.Type type,UnityAction<Object> callBack ) { StartCoroutine(ReallyLoadResAsync(abName,resName,type,callBack)); } private IEnumerator ReallyLoadResAsync (string abName,string resName,System.type,UnityAction<Object> callBack ) { LoadAB(abName); var abr = abDic[abName].LoadAssetAsync(resName,type); yield return abr; callBack(abr.asset); } public void LoadResAsync <T >(string abName,string resName,UnityAction<T> callBack ) where T:object { StartCoroutine(ReallyLoadResAsync<T>(abName,resName,callBack)); } private IEnumerator ReallyLoadResAsync <T >(string abName,string resName,UnityAction<T> callBack ) { LoadAB(abName); var abr = abDic[abName].LoadAssetAsync<T>(resName); yield return abr; callBack(abr.asset as T); } public void UnLoad (string abName ) { if (abDic.ContainsKey(abName)) { abDic[abName].Unload(false ); abDic.Remove(abName); } } public void ClearAb () { AssetBundle.UnloadAllAssetBundles(false ); abDic.Clear(); maniAB = null ; manifest = null ; } }
宏定义:在不同的环境下执行不同的代码,比如在安卓平台和在苹果平台下执行不同的代码,这样你就可以专门为你的目标平台编译代码
使用AB包资源管理器
1 2 3 4 5 6 7 void Start (){ var obj = ABMgr.Instance.LoadRec("model" ,"Cube" ); Instantiate(obj); obj = ABMgr.Instance.LoadRec("model" ,"Cube" ,typeof (GameObject)) as GameObject; obj = ABMgr.Instance.LoadRec<GameObject>("model" ,"Cube" ); }