基于Unity2017版本的AB技術(shù)
1.項(xiàng)目中成百上千的大量資源需要(批量)打包處理,不可能手工維護(hù)方式給每個(gè)資源添加ab"包名稱"
2.Unity對(duì)包依賴關(guān)系不是很完善
如果要加載一個(gè)多重依賴項(xiàng)的AB包,需要手工寫(xiě)代碼,把底層所有依賴包關(guān)系需要預(yù)先進(jìn)行加載后才可以。
3.AB包商業(yè)應(yīng)用 步驟有 AB包加載 AB包依賴關(guān)系(不遺漏、不重復(fù)) 資源提取釋放。繁重海量 手動(dòng)寫(xiě)工作效率低下
4.可能會(huì)反復(fù)加載同一AB包中資源 導(dǎo)致加載過(guò)慢
AB框架包括自動(dòng)標(biāo)記腳本、創(chuàng)建與銷毀打包資源、單一AB包加載
與測(cè)試腳本、專門(mén)讀取manifest維護(hù)AB包依賴關(guān)系,實(shí)現(xiàn)遞歸依賴加載機(jī)制的腳本

自動(dòng)創(chuàng)建AB包分類依據(jù) 按照?qǐng)鼍胺诸?br> 命名規(guī)則 場(chǎng)景名稱/功能文件夾
在Editor類添加自動(dòng)添加標(biāo)記類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AutoSetLables.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: AB打包工具
* 定義需要打包資源的文件夾根目錄
* 遍歷每個(gè)"場(chǎng)景"文件夾
* 遍歷本場(chǎng)景目錄下所有目錄或者文件
* 如果是目錄,則繼續(xù)遞歸訪問(wèn),直到定位到文件
* 找到文件,則使用AssetImporter類 標(biāo)記包名、后綴名
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace ABFrameWork
{
public class AutoSetLables
{
/// <summary>
/// 設(shè)置AB包名
/// </summary>
[MenuItem("ABTools/SetABLable")]
public static void SetABLable()
{
string strNeedSetLableRoot = string.Empty;
//根目錄下所有場(chǎng)景目錄
DirectoryInfo[] dirSencesDIRArray;
//清空無(wú)用AB標(biāo)記
AssetDatabase.RemoveUnusedAssetBundleNames();
strNeedSetLableRoot = PathTools.GetABResourcesPath();
//獲取路徑下所有文件夾
DirectoryInfo directoryInfo = new DirectoryInfo(strNeedSetLableRoot);
dirSencesDIRArray = directoryInfo.GetDirectories();
foreach (var item in dirSencesDIRArray)
{
string tmpSencesDIR = strNeedSetLableRoot + "/" + item.Name;
int tmpIndex = tmpSencesDIR.LastIndexOf("/");
string tmpScenesName = tmpSencesDIR.Substring(tmpIndex + 1);
JudgeDIRorFileByRecursive(item, tmpScenesName);
}
AssetDatabase.Refresh();
Debug.Log("AB設(shè)置標(biāo)記完成");
}
/// <summary>
/// 遞歸判斷是否為目錄與文件,修改AB標(biāo)記
/// </summary>
/// <param name="currentDIR">當(dāng)前文件信息 (和目錄信息可以相互轉(zhuǎn)換)</param>
/// <param name="scenesName"></param>
static void JudgeDIRorFileByRecursive(FileSystemInfo fileSystemInfo, string scenesName)
{
if (!fileSystemInfo.Exists)
{
Debug.LogError("目錄或文件名稱" + fileSystemInfo + "不存在,請(qǐng)檢查");
return;
}
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
foreach (var item in fileSystemInfos)
{
FileInfo fileInfo = item as FileInfo;
if (fileInfo != null)
{
//修改AB標(biāo)簽
SetFileABLable(fileInfo, scenesName);
}
else
{
JudgeDIRorFileByRecursive(item, scenesName);
}
}
}
static void SetFileABLable(FileInfo fileInfo, string scenesName)
{
//AB包名
string ABName = string.Empty;
string assetFilePath = string.Empty;
//檢查后綴
if (fileInfo.Extension==".meta")
return;
ABName = GetABName(fileInfo, scenesName);
//截取到Asset之后的目錄
int tmpIndex = fileInfo.FullName.IndexOf("Assets");
assetFilePath = fileInfo.FullName.Substring(tmpIndex);
//給資源文件設(shè)置AB名稱及后綴
AssetImporter tmpImpObj = AssetImporter.GetAtPath(assetFilePath);
tmpImpObj.assetBundleName = ABName;
if (fileInfo.Extension==".unity")
{
//定義AB包擴(kuò)展名
tmpImpObj.assetBundleVariant = "u3d";
}
else
{
tmpImpObj.assetBundleVariant = "ab";
}
}
/// <summary>
/// 返回合法AB包名稱
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="scenesName"></param>
/// <returns></returns>
static string GetABName(FileInfo fileInfo,string scenesName)
{
string ABName = string.Empty;
//Win路徑
string tmpWinPath = fileInfo.FullName;
//Unity路徑
string tmpUnityPath = tmpWinPath.Replace("\\", "/");
//定位"場(chǎng)景名稱"后面字符位置
int tmpScenceNamePos = tmpUnityPath.IndexOf(scenesName)+scenesName.Length;
//AB包中"類型名稱"所在區(qū)域
string strABFileNameArea=tmpUnityPath.Substring(tmpScenceNamePos+1);
if (strABFileNameArea.Contains("/"))
{
string[] tempStrArray = strABFileNameArea.Split('/');
ABName = scenesName + "/" +tempStrArray[0];
}
else
{
//sences特殊名字
ABName = scenesName + "/" + scenesName;
}
return ABName;
}
}
}
把路徑定義為常量類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: PathTools.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: 路徑工具類
* 包含路徑常量
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class PathTools
{
public const string AB_ResourcesPath = "AB_Res";
public static string GetABResourcesPath()
{
return Application.dataPath + "/" + AB_ResourcesPath;
}
}
}
然后添加本地加載和WebReq加載單個(gè)資源
Editor腳本
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AutoSetLables.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: AB打包工具
* 定義需要打包資源的文件夾根目錄
* 遍歷每個(gè)"場(chǎng)景"文件夾
* 遍歷本場(chǎng)景目錄下所有目錄或者文件
* 如果是目錄,則繼續(xù)遞歸訪問(wèn),直到定位到文件
* 找到文件,則使用AssetImporter類 標(biāo)記包名、后綴名
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace ABFrameWork
{
public class DeleteAB
{
[MenuItem("ABTools/DeleteAllAB")]
public static void DeleteAllAB()
{
string strABNeedPathDir = string.Empty;
strABNeedPathDir = PathTools.GetABOutPath();
if (!string.IsNullOrEmpty(strABNeedPathDir))
{
//這里參數(shù)true表示可以刪除非空目錄
Directory.Delete(strABNeedPathDir,true);
File.Delete(strABNeedPathDir+".meta");
AssetDatabase.Refresh();
}
}
}
public class BuildAB
{
[MenuItem("ABTools/BuildAllAB")]
public static void BuildAllAB()
{
string strABOutPathDir = string.Empty;
strABOutPathDir = PathTools.GetABOutPath();
if (!Directory.Exists(strABOutPathDir))
{
Directory.CreateDirectory(strABOutPathDir);
}
BuildPipeline.BuildAssetBundles(strABOutPathDir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
AssetDatabase.Refresh();
}
}
public class AutoSetLables
{
/// <summary>
/// 設(shè)置AB包名
/// </summary>
[MenuItem("ABTools/SetABLable")]
public static void SetABLable()
{
string strNeedSetLableRoot = string.Empty;
//根目錄下所有場(chǎng)景目錄
DirectoryInfo[] dirSencesDIRArray;
//清空無(wú)用AB標(biāo)記
AssetDatabase.RemoveUnusedAssetBundleNames();
strNeedSetLableRoot = PathTools.GetABResourcesPath();
//獲取路徑下所有文件夾
DirectoryInfo directoryInfo = new DirectoryInfo(strNeedSetLableRoot);
dirSencesDIRArray = directoryInfo.GetDirectories();
foreach (var item in dirSencesDIRArray)
{
string tmpSencesDIR = strNeedSetLableRoot + "/" + item.Name;
int tmpIndex = tmpSencesDIR.LastIndexOf("/");
string tmpScenesName = tmpSencesDIR.Substring(tmpIndex + 1);
JudgeDIRorFileByRecursive(item, tmpScenesName);
}
AssetDatabase.Refresh();
Debug.Log("AB設(shè)置標(biāo)記完成");
}
/// <summary>
/// 遞歸判斷是否為目錄與文件,修改AB標(biāo)記
/// </summary>
/// <param name="currentDIR">當(dāng)前文件信息 (和目錄信息可以相互轉(zhuǎn)換)</param>
/// <param name="scenesName"></param>
static void JudgeDIRorFileByRecursive(FileSystemInfo fileSystemInfo, string scenesName)
{
if (!fileSystemInfo.Exists)
{
Debug.LogError("目錄或文件名稱" + fileSystemInfo + "不存在,請(qǐng)檢查");
return;
}
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
foreach (var item in fileSystemInfos)
{
FileInfo fileInfo = item as FileInfo;
if (fileInfo != null)
{
//修改AB標(biāo)簽
SetFileABLable(fileInfo, scenesName);
}
else
{
JudgeDIRorFileByRecursive(item, scenesName);
}
}
}
static void SetFileABLable(FileInfo fileInfo, string scenesName)
{
//AB包名
string ABName = string.Empty;
string assetFilePath = string.Empty;
//檢查后綴
if (fileInfo.Extension == ".meta")
return;
ABName = GetABName(fileInfo, scenesName);
//截取到Asset之后的目錄
int tmpIndex = fileInfo.FullName.IndexOf("Assets");
assetFilePath = fileInfo.FullName.Substring(tmpIndex);
//給資源文件設(shè)置AB名稱及后綴
AssetImporter tmpImpObj = AssetImporter.GetAtPath(assetFilePath);
tmpImpObj.assetBundleName = ABName;
if (fileInfo.Extension == ".unity")
{
//定義AB包擴(kuò)展名
tmpImpObj.assetBundleVariant = "u3d";
}
else
{
tmpImpObj.assetBundleVariant = "ab";
}
}
/// <summary>
/// 返回合法AB包名稱
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="scenesName"></param>
/// <returns></returns>
static string GetABName(FileInfo fileInfo, string scenesName)
{
string ABName = string.Empty;
//Win路徑
string tmpWinPath = fileInfo.FullName;
//Unity路徑
string tmpUnityPath = tmpWinPath.Replace("\\", "/");
//定位"場(chǎng)景名稱"后面字符位置
int tmpScenceNamePos = tmpUnityPath.IndexOf(scenesName) + scenesName.Length;
//AB包中"類型名稱"所在區(qū)域
string strABFileNameArea = tmpUnityPath.Substring(tmpScenceNamePos + 1);
if (strABFileNameArea.Contains("/"))
{
string[] tempStrArray = strABFileNameArea.Split('/');
ABName = scenesName + "/" + tempStrArray[0];
}
else
{
//sences特殊名字
ABName = scenesName + "/" + scenesName;
}
return ABName;
}
}
}
工具路徑類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: PathTools.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: 路徑工具類
* 包含路徑常量
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class PathTools
{
public const string AB_ResourcesPath = "AB_Res";
/// <summary>
/// 獲取AB標(biāo)記路徑
/// </summary>
/// <returns></returns>
public static string GetABResourcesPath()
{
return Application.dataPath + "/" + AB_ResourcesPath;
}
/// <summary>
/// 獲取AB輸出路徑
/// 1.平臺(tái)(PC/移動(dòng))路徑
/// </summary>
public static string GetABOutPath()
{
return GetPlatfromPath()+"/"+ GetPlatfromName();
}
/// <summary>
/// 獲取平臺(tái)路徑
/// </summary>
/// <returns></returns>
public static string GetPlatfromPath()
{
string strReturnPlatformPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformPath = Application.streamingAssetsPath;
break;
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.Android:
strReturnPlatformPath = Application.persistentDataPath;
break;
}
return strReturnPlatformPath;
}
/// <summary>
/// 獲取平臺(tái)名稱
/// </summary>
/// <returns></returns>
public static string GetPlatfromName()
{
string strReturnPlatformName = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformName = "Windows";
break;
case RuntimePlatform.IPhonePlayer:
strReturnPlatformName = "IPhone";
break;
case RuntimePlatform.Android:
strReturnPlatformName = "Android";
break;
}
return strReturnPlatformName;
}
public static string GetWWWPath()
{
string strWWWPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strWWWPath = "file://"+GetABOutPath();
break;
case RuntimePlatform.IPhonePlayer:
break;
case RuntimePlatform.Android:
strWWWPath = "jar:file://" + GetABOutPath();
break;
}
return strWWWPath;
}
}
}
加載資源類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AssetLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description:
* 管理與加載指定AB資源
* 加載具有"緩存功能"的資源 帶選用參數(shù)
* 卸載、釋放AB資源
* 查看當(dāng)前AB的資源
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class AssetLoader : System.IDisposable
{
AssetBundle currentAB;
/// <summary>
/// 緩存容器
/// </summary>
Hashtable ht=new Hashtable();
public AssetLoader(AssetBundle abObj)
{
if (abObj != null)
{
currentAB = abObj;
}
else
{
Debug.LogError($"{GetType()}/AssetLoader/abObj= null,please check!");
}
}
/// <summary>
/// 加載當(dāng)前包中指定數(shù)據(jù)
/// </summary>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string assetName, bool isCache = false)
{
return LoadRes<Object>(assetName, isCache);
}
T LoadRes<T>(string assetName, bool isCache) where T : Object
{
//是否緩存集合已經(jīng)存在
if (ht.Contains(assetName))
{
return ht[assetName] as T;
}
//正式加載
T tmpRes = currentAB.LoadAsset<T>(assetName);
if (tmpRes != null && isCache)
{
ht.Add(assetName, tmpRes);
}
else if (tmpRes == null)
{
Debug.LogError($"{GetType()}/LoadRes<T>/tmpRes == null,please check!");
}
return tmpRes;
}
/// <summary>
/// 卸載指定的資源
/// </summary>
public bool UnLoadAsset(Object asset)
{
if (asset != null)
{
Resources.UnloadAsset(asset);
return true;
}
Debug.LogError($"{GetType()}/UnLoadAsset/asset == null,please check!");
return false;
}
/// <summary>
/// 釋放當(dāng)前AB內(nèi)存鏡像資源
/// </summary>
public void Dispose()
{
currentAB.Unload(false);
}
/// <summary>
/// 釋放當(dāng)前AB內(nèi)存鏡像資源,且釋放內(nèi)存資源
/// </summary>
public void DisposeAll()
{
currentAB.Unload(true);
}
/// <summary>
/// 查詢當(dāng)前AB包包含的所有資源名稱
/// </summary>
/// <returns></returns>
public string[] RetriveAllAssetName()
{
return currentAB.GetAllAssetNames();
}
}
}
網(wǎng)上加載資源類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SingleAssetLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace ABFrameWork
{
public class SingleAssetLoader : System.IDisposable
{
/// <summary>
/// 引用類資源加載
/// </summary>
AssetLoader assetLoader;
DelLoadComplete loadCompleteHandle;
string ABName;
string ABDownLoadPath;
public SingleAssetLoader(string abName, DelLoadComplete loadComplete)
{
ABName = abName;
loadCompleteHandle = loadComplete;
ABDownLoadPath = PathTools.GetWWWPath() + "/" + abName;
}
public IEnumerator LoadAB()
{
using (UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(ABDownLoadPath))
{
yield return req.SendWebRequest();
if (req.downloadProgress >= 1)
{
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(req);
if (ab != null)
{
assetLoader = new AssetLoader(ab);
loadCompleteHandle?.Invoke(ABName);
}
else
{
Debug.LogError($"{GetType() }/ LoadAB() loadError ,please check! the{ABDownLoadPath} should be null");
}
}
}
}
/// <summary>
/// 加載AB包指定資源
/// </summary>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string assetName, bool isCache)
{
if (assetLoader != null)
{
return assetLoader.LoadAsset(assetName, isCache);
}
Debug.LogError($"{GetType() }/LoadAsset() assetLoader==null,please check!");
return null;
}
/// <summary>
/// 卸載AB包指定資源
/// </summary>
/// <param name="asset"></param>
public void UnLoadAsset(Object asset)
{
if (assetLoader != null)
{
assetLoader.UnLoadAsset(asset);
}
else
{
Debug.LogError($"{GetType() }/UnLoadAsset(Object asset) assetLoader==null,please check!");
}
}
/// <summary>
/// 釋放資源
/// </summary>
public void Dispose()
{
if (assetLoader != null)
{
assetLoader.Dispose();
}
else
{
Debug.LogError($"{GetType() }/Dispose() assetLoader==null,please check!");
}
}
public void DisposeAll()
{
if (assetLoader != null)
{
assetLoader.DisposeAll();
}
else
{
Debug.LogError($"{GetType() }/DisposeAll() assetLoader==null,please check!");
}
}
/// <summary>
/// 查詢AB包中所有資源
/// </summary>
/// <returns></returns>
public string[] RetrivalAllAssetName()
{
if (assetLoader != null)
{
return assetLoader.RetriveAllAssetName();
}
Debug.LogError($"{GetType() }/etrivalAllAssetName() assetLoader==null,please check!");
return null;
}
}
}
常量類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABDefine.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 工具類
* 本項(xiàng)目所有的常量
* 所有的委托定義
* 枚舉定義
* 常量定義
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public delegate void DelLoadComplete(string abName);
/// <summary>
/// 框架常量
/// </summary>
public class ABDefine
{
}
}
測(cè)試類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: TestAB.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 測(cè)試類
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ABFrameWork;
public class TestAB : MonoBehaviour
{
string abName = "sences_1/prefabs.ab";
string assetName = "Cube.prefab";
SingleAssetLoader loader;
// Start is called before the first frame update
void Start()
{
loader = new SingleAssetLoader(abName, (abName) =>
{
var a = loader.LoadAsset(assetName, false);
Instantiate(a);
});
StartCoroutine(loader.LoadAB());
}
// Update is called once per frame
void Update()
{
}
}

因?yàn)闆](méi)有依賴資源 所以丟失了材質(zhì)
所以要先加載材質(zhì)貼圖再加載預(yù)制體
需要有一個(gè)處理依賴關(guān)系的類
獲取Manifest里面的依賴

維護(hù)包與包之間的關(guān)系
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABManifestLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: 讀取AB的依賴關(guān)系(Windows.mainfest)
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace ABFrameWork
{
public class ABManifestLoader : Singleton<ABManifestLoader>,System.IDisposable
{
/// <summary>
/// 系統(tǒng)ab清單文件
/// </summary>
AssetBundleManifest manifest;
/// <summary>
/// ab清單文件路徑
/// </summary>
string strManifestPath;
/// <summary>
/// 讀取AB清單文件的AB
/// </summary>
AssetBundle ABReadManifest;
public bool isLoadFinish { get; private set; } = false;
public ABManifestLoader()
{
strManifestPath = PathTools.GetWWWPath() + "/" + PathTools.GetPlatfromName();
}
/// <summary>
/// 加載Mainfest清單文件
/// </summary>
/// <returns></returns>
public IEnumerator LoadMainfestFile()
{
using (UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(strManifestPath))
{
yield return req.SendWebRequest();
if (req.downloadProgress >= 1)
{
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(req);
if (ab != null)
{
ABReadManifest = ab;
manifest = ab.LoadAsset(ABDefine.ASSETBUNLDE_MANIFEST) as AssetBundleManifest;
isLoadFinish = true;
}
else
{
Debug.LogError($"{GetType()}/LoadMainfestFile() downLoad Error, please check{strManifestPath}");
}
}
}
}
/// <summary>
/// 獲取ABManifest
/// </summary>
/// <returns></returns>
public AssetBundleManifest GetABManifest()
{
if (isLoadFinish)
{
if (manifest != null)
{
return manifest;
}
else
{
Debug.LogError($"{GetType()}/GetABManifest() manifest==null, please check");
}
}
else
{
Debug.LogError($"{GetType()}/GetABManifest() isLoadFinish==false, please check");
}
return null;
}
/// <summary>
/// 獲取ABManifest系統(tǒng)類的依賴項(xiàng)
/// </summary>
/// <param name="abName"></param>
/// <returns></returns>
public string[] RetrivalDependce(string abName)
{
if (!string.IsNullOrEmpty(abName))
{
return manifest?.GetAllDependencies(abName);
}
return null;
}
/// <summary>
/// 釋放本類資源
/// </summary>
public void Dispose()
{
ABReadManifest?.Unload(true);
}
}
}
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABRelation.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: AB關(guān)系類
* 儲(chǔ)存制定AB包的所有依賴關(guān)系包
* 儲(chǔ)存制定AB包所有的引用關(guān)系包
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class ABRelation
{
string ABName;
List<string> allDependenceAB=new List<string>();
List<string> allReferenceAB=new List<string>();
public ABRelation(string ABName)
{
this.ABName = ABName;
}
/// <summary>
/// 增加依賴關(guān)系
/// </summary>
/// <param name="Name"></param>
public void AddDependence(string abName)
{
if (!allDependenceAB.Contains(abName))
{
allDependenceAB.Add(abName);
}
}
/// <summary>
/// 移除依賴關(guān)系
/// </summary>
/// <param name="abName"></param>
/// true 此AB包沒(méi)有依賴項(xiàng)
/// false 此AB包還有其他的依賴項(xiàng)
/// <returns></returns>
public bool RemoveDependence(string abName)
{
if (allDependenceAB.Contains(abName))
{
allDependenceAB.Remove(abName);
}
if (allDependenceAB.Count>0)
return false;
else
return true;
}
public List<string>GetAllDependence()
{
return allDependenceAB;
}
/// <summary>
/// 增加引用關(guān)系
/// </summary>
/// <param name="Name"></param>
public void AddReference(string abName)
{
if (!allReferenceAB.Contains(abName))
{
allReferenceAB.Add(abName);
}
}
/// <summary>
/// 移除引用關(guān)系
/// </summary>
/// <param name="abName"></param>
/// true 此AB包沒(méi)有依賴項(xiàng)
/// false 此AB包還有其他的依賴項(xiàng)
/// <returns></returns>
public bool RemoveReference(string abName)
{
if (allReferenceAB.Contains(abName))
{
allReferenceAB.Remove(abName);
}
if (allReferenceAB.Count > 0)
return false;
else
return true;
}
public List<string> GetAllReference()
{
return allReferenceAB;
}
}
}
一個(gè)場(chǎng)景多個(gè)包之間的關(guān)系
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: MultABMgr.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: 針對(duì)一個(gè)場(chǎng)景中關(guān)于多個(gè)AB綜合管理
* 獲取AB包之間的依賴關(guān)系和引用關(guān)系
* 管理AB包之間的自動(dòng)連接(遞歸加載機(jī)制)
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class MultABMgr
{
/// <summary>
/// 引用類 "單個(gè)AB包加載實(shí)現(xiàn)"
/// </summary>
SingleAssetLoader currentSingleABLoader;
/// <summary>
/// Ab包緩存集合(防止重復(fù)加載)
/// </summary>
Dictionary<string, SingleAssetLoader> singleABLoaderCache = new Dictionary<string, SingleAssetLoader>();
/// <summary>
/// 當(dāng)前場(chǎng)景(調(diào)用使用)
/// </summary>
string currentScenceName;
/// <summary>
/// Ab包名
/// </summary>
string currentABName;
/// <summary>
/// AB包與對(duì)應(yīng)依賴關(guān)系集合
/// </summary>
Dictionary<string, ABRelation> abRelation = new Dictionary<string, ABRelation>();
/// <summary>
/// 所有AB包加載完成回調(diào)
/// </summary>
DelLoadComplete LoadALLABPackageCompleteHandel;
public MultABMgr(string senceName, string abName, DelLoadComplete loadAllABPackCompleteHandle)
{
currentScenceName = senceName;
currentABName = abName;
LoadALLABPackageCompleteHandel = loadAllABPackCompleteHandle;
}
/// <summary>
/// 完成指定AB包調(diào)用
/// </summary>
/// <param name="name"></param>
void CompleteLoadAB(string abName)
{
if (abName.Equals(currentABName))
{
LoadALLABPackageCompleteHandel?.Invoke(abName);
}
}
public IEnumerator LoadAB(string abName)
{
ABRelation abRel;
//AB包關(guān)系建立
if (!abRelation.ContainsKey(abName))
{
abRel = new ABRelation(abName);
abRelation.Add(abName, abRel);
}
abRel = abRelation[abName];
//得到指定AB包所有依賴關(guān)系(查詢Manifest清單文件)
string[] strDependeceArray = ABManifestLoader.Instance.RetrivalDependce(abName);
foreach (var item in strDependeceArray)
{
//添加依賴項(xiàng)
abRel.AddDependence(item);
//加載引用項(xiàng)(遞歸調(diào)用)
yield return LoadReference(item, abName);
}
//加載AB包
if (singleABLoaderCache.ContainsKey(abName))
{
yield return singleABLoaderCache[abName].LoadAB();
}
else
{
currentSingleABLoader = new SingleAssetLoader(abName, CompleteLoadAB);
singleABLoaderCache.Add(abName,currentSingleABLoader);
yield return currentSingleABLoader.LoadAB();
}
yield return null;
}
/// <summary>
/// 加載引用AB包
/// </summary>
/// <param name="abName">ab包名稱</param>
/// <param name="refName">被引用AB包名稱</param>
/// <returns></returns>
IEnumerator LoadReference(string abName, string refName)
{
ABRelation tmpABRelation;
if (abRelation.ContainsKey(abName))
{
tmpABRelation = abRelation[abName];
//添加AB包引用關(guān)系(被依賴)
tmpABRelation.AddReference(refName);
}
else
{
tmpABRelation = new ABRelation(abName);
tmpABRelation.AddReference(refName);
abRelation.Add(abName, tmpABRelation);
//開(kāi)始加載依賴包(遞歸)
yield return LoadAB(abName);
}
yield return null;
}
/// <summary>
/// 加載AB包中資源
/// </summary>
/// <param name="abName"></param>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string abName, string assetName, bool isCache)
{
foreach (var item in singleABLoaderCache.Keys)
{
if (abName == item)
{
return singleABLoaderCache[item].LoadAsset(assetName, isCache);
}
}
Debug.LogError(GetType() + $"/LoadAsset()/do not find AB please check! abName{abName} assetName{assetName}");
return null;
}
public void DisposeAllAsset()
{
try
{
//逐一釋放所有加載過(guò)的AB包中資源
foreach (var item in singleABLoaderCache.Values)
{
item.DisposeAll();
}
}
finally
{
singleABLoaderCache.Clear();
singleABLoaderCache = null;
//釋放其他對(duì)象占用資源
abRelation.Clear();
abRelation = null;
currentABName = null;
currentScenceName = null;
LoadALLABPackageCompleteHandel = null;
//卸載沒(méi)有用到的資源
Resources.UnloadUnusedAssets();
//強(qiáng)制垃圾收集
System.GC.Collect();
}
}
}
}

最后封裝一層調(diào)用類
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABMgr.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-19
*Description: 多包管理按場(chǎng)景加載
* 讀取清單文件 緩存腳本
* 以場(chǎng)景為單位 管理整個(gè)項(xiàng)目中所有AB包
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class ABMgr : SingletonM<ABMgr>
{
//場(chǎng)景集合
Dictionary<string, MultABMgr> allScenes = new Dictionary<string, MultABMgr>();
//AB清單文件
AssetBundleManifest manifest;
protected override void Awake()
{
base.Awake();
StartCoroutine(ABManifestLoader.Instance.LoadMainfestFile());
}
public IEnumerator LoadAB(string sencesName, string abName, DelLoadComplete loadAllCompleteHandle)
{
//參數(shù)檢查
if (string.IsNullOrEmpty(sencesName) || string.IsNullOrEmpty(abName))
{
Debug.LogError(GetType() + "/LoadAB()/sencesName or abName==null,please check!");
}
//等待Manifest清單文件加載完成
while (!ABManifestLoader.Instance.isLoadFinish)
{
yield return null;
}
manifest = ABManifestLoader.Instance.GetABManifest();
if (manifest == null)
{
Debug.LogError(GetType() + "/LoadAB()/manifest==null,please check!");
yield return null;
}
MultABMgr multABMgr;
//把當(dāng)前場(chǎng)景加入到集合中
if (!allScenes.ContainsKey(sencesName))
{
multABMgr = new MultABMgr(sencesName, abName, loadAllCompleteHandle);
allScenes.Add(sencesName, multABMgr);
}
//調(diào)用下一層(多包管理員)
multABMgr = allScenes[sencesName];
if (multABMgr == null)
{
Debug.LogError(GetType() + "/LoadAB()/multABMgr==null,please check!");
}
//調(diào)用多包管理類的加載指定AB包
yield return multABMgr.LoadAB(abName);
}
/// <summary>
/// 加載AB包資源
/// </summary>
/// <param name="scenesName">場(chǎng)景名</param>
/// <param name="abName">包名</param>
/// <param name="assetName">資源名</param>
/// <param name="isCache">是否緩存</param>
/// <returns></returns>
public Object LoadAsset(string scenesName, string abName, string assetName, bool isCache)
{
if (allScenes.ContainsKey(scenesName))
{
MultABMgr multABMgr = allScenes[scenesName];
return multABMgr.LoadAsset(abName, assetName, isCache);
}
Debug.LogError(GetType() + $"/LoadAsset()do not find scenes,can't loadAsset, scenesName={scenesName}");
return null;
}
/// <summary>
/// 加載AB包資源
/// </summary>
/// <param name="scenesName">場(chǎng)景名</param>
/// <param name="abName">包名</param>
/// <param name="assetName">資源名</param>
/// <param name="isCache">是否緩存</param>
/// <returns></returns>
public void DisposeAllAssets(string scenesName)
{
if (allScenes.ContainsKey(scenesName))
{
MultABMgr multABMgr = allScenes[scenesName];
multABMgr.DisposeAllAsset();
}
else
{
Debug.LogError(GetType() + $"/DisposeAllAssets()do not find scenes,can't DisposeAllAssets, scenesName={scenesName}");
}
}
}
}
測(cè)試類 根據(jù)場(chǎng)景名 包名 預(yù)制體名字 加載
好像是有點(diǎn)麻煩
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: TestAB.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 測(cè)試類
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ABFrameWork;
public class TestAB : MonoBehaviour
{
//string abName = "sences_1/prefabs.ab";
//string assetName = "Cube.prefab";
//SingleAssetLoader loader;
string scenesName = "scence_1";
string abName = "sences_1/prefabs.ab";
string assetName = "Cube.prefab";
void Start()
{
//loader = new SingleAssetLoader(abName, (abName) =>
//{
// var a = loader.LoadAsset(assetName, false);
// Instantiate(a);
//});
//StartCoroutine(loader.LoadAB());
StartCoroutine(ABMgr.Instance.LoadAB(scenesName, abName, (abName) =>
{
Object tmpObj = ABMgr.Instance.LoadAsset(scenesName, abName, assetName, false);
if (tmpObj != null)
{
Instantiate(tmpObj);
}
}));
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
ABMgr.Instance.DisposeAllAssets(scenesName);
}
}
}

釋放后

里面用到一個(gè)單例類之后放出源碼
https://github.com/1004019267/ABFrameWorkWithSence