Unity批量打AB包
為了資源熱更新,Unity支援將所有資源打包成AssetBundle資源,存放在SteamingAssets資料夾中;
在專案釋出之前,需要將所有資源打包成.ab檔案,動態載入;
在專案更新時,替換.ab資原始檔,即可完成熱更新;
ab檔案在載入時,會多一步解壓縮的過程,會增加效能消耗;
打包操作屬於編輯器擴充,所有指令碼放在Eidtor資料夾下;
1.PathTool
根據不同平臺,獲取ab輸出和輸入路徑;
不同平臺的輸入輸出路徑不相同,ios,android,windows;《Unity資原始檔夾介紹》
public class PathTools
{
// 打包AB包根路徑
public const string AB_RESOURCES = "StreamingAssets";
// 得到 AB 資源的輸入目錄
public static string GetABResourcesPath()
{
return Application.dataPath + "/" + AB_RESOURCES;
}
// 獲得 AB 包輸出路徑
public static string GetABOutPath()
{
return GetPlatformPath() + "/" + GetPlatformName();
}
//獲得平臺路徑
private static string GetPlatformPath()
{
string strReturenPlatformPath = string.Empty;
#if UNITY_STANDALONE_WIN
strReturenPlatformPath = Application.streamingAssetsPath;
#elif UNITY_IPHONE
strReturenPlatformPath = Application.persistentDataPath;
#elif UNITY_ANDROID
strReturenPlatformPath = Application.persistentDataPath;
#endif
return strReturenPlatformPath;
}
// 獲得平臺名稱
public static string GetPlatformName()
{
string strReturenPlatformName = string.Empty;
#if UNITY_STANDALONE_WIN
strReturenPlatformName = "Windows";
#elif UNITY_IPHONE
strReturenPlatformName = "IPhone";
#elif UNITY_ANDROID
strReturenPlatformName = "Android";
#endif
return strReturenPlatformName;
}
// 返回 WWW 下載 AB 包載入路徑
public static string GetWWWAssetBundlePath()
{
string strReturnWWWPath = string.Empty;
#if UNITY_STANDALONE_WIN
strReturnWWWPath = "file://" + GetABOutPath();
#elif UNITY_IPHONE
strReturnWWWPath = GetABOutPath() + "/Raw/";
#elif UNITY_ANDROID
strReturnWWWPath = "jar:file://" + GetABOutPath();
#endif
return strReturnWWWPath;
}
}
2.CreateAB
功能:選中一個資料夾,將該資料夾中所有資原始檔打包成AB檔案;
主要邏輯:遍歷資料夾中所有檔案,是檔案的生成AssetBundleBuild存在連結串列中統一打包,是資料夾的遞迴上一步操作,將所有資原始檔都放在listassets連結串列中;
官方Api:BuildPipeline.BuildAssetBundles統一打包所有資源;
public class CreateAB : MonoBehaviour
{
private static string abOutPath;
private static List<AssetBundleBuild> listassets = new List<AssetBundleBuild>();
private static List<DirectoryInfo> listfileinfo = new List<DirectoryInfo>();
private static bool isover = false; //是否檢查完成,可以打包
static private string selectPath;
public static bool GetState()
{
return isover;
}
public static AssetBundleBuild[] GetAssetBundleBuilds()
{
return listassets.ToArray();
}
[MenuItem("ABTools/CreatAB &_Q", false)]
public static void CreateModelAB()
{
abOutPath = Application.streamingAssetsPath;
if (!Directory.Exists(abOutPath))
Directory.CreateDirectory(abOutPath);
UnityEngine.Object obj = Selection.activeObject;
selectPath = AssetDatabase.GetAssetPath(obj);
SearchFileAssetBundleBuild(selectPath);
BuildPipeline.BuildAssetBundles(abOutPath,
CreateAB.GetAssetBundleBuilds(), BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
Debug.Log("AssetBundle打包完畢");
}
[MenuItem("ABTools/CreatAB &_Q", true)]
public static bool CanCreatAB()
{
if (Selection.objects.Length > 0)
{
return true;
}
else
return false;
}
這裡為什麼會紅我也不知道...
//是檔案,繼續向下
public static void SearchFileAssetBundleBuild(string path)
{
DirectoryInfo directory = new DirectoryInfo(@path);
FileSystemInfo[] fileSystemInfos = directory.GetFileSystemInfos();
listfileinfo.Clear();
//遍歷所有資料夾中所有檔案
foreach (var item in fileSystemInfos)
{
int idx = item.ToString().LastIndexOf(@"\");
string name = item.ToString().Substring(idx + 1);
//item為資料夾,新增進listfileinfo,遞迴呼叫
if ((item as DirectoryInfo) != null)
listfileinfo.Add(item as DirectoryInfo);
//剔除meta檔案,其他檔案都建立AssetBundleBuild,新增進listassets;
if (!name.Contains(".meta"))
{
CheckFileOrDirectoryReturnBundleName(item, path + "/" + name);
}
}
if (listfileinfo.Count == 0)
isover = true;
else
{
Debug.LogError(listfileinfo.Count);
}
}
//判斷是檔案還是資料夾
public static string CheckFileOrDirectoryReturnBundleName(FileSystemInfo fileSystemInfo, string path)
{
FileInfo fileInfo = fileSystemInfo as FileInfo;
if (fileInfo != null)
{
string[] strs = path.Split('.');
string[] dictors = strs[0].Split('/');
string name = "";
for (int i = 1; i < dictors.Length; i++)
{
if (i < dictors.Length - 1)
{
name += dictors[i] + "/";
}
else
{
name += dictors[i];
}
}
string[] strName = selectPath.Split('/');
AssetBundleBuild assetBundleBuild = new AssetBundleBuild();
assetBundleBuild.assetBundleName = strName[strName.Length - 1];
assetBundleBuild.assetBundleVariant = "ab";
assetBundleBuild.assetNames = new string[] {path};
listassets.Add(assetBundleBuild);
return name;
}
else
{
//遞迴呼叫
SearchFileAssetBundleBuild(path);
return null;
}
}
}
3.ClearABLable
打包時每個資源會新增一個標籤,如果重複打包,需要清空才可再次打包,否則會失敗;
使用官方API:AssetDatabase.RemoveUnusedAssetBundleNames();
因為註釋寫的很詳細,就不贅述了;
public class ClearABLable
{
[MenuItem("ABTools/Remove AB Label")]
public static void RemoveABLabel()
{
// 需要移除標記的根目錄
string strNeedRemoveLabelRoot = string.Empty;
// 目錄資訊(場景目錄資訊陣列,表示所有根目錄下場景目錄)
DirectoryInfo[] directoryDIRArray = null;
// 定義需要移除AB標籤的資源的資料夾根目錄
strNeedRemoveLabelRoot = PathTools.GetABResourcesPath();
DirectoryInfo dirTempInfo = new DirectoryInfo(strNeedRemoveLabelRoot);
directoryDIRArray = dirTempInfo.GetDirectories();
// 遍歷本場景目錄下所有的目錄或者檔案
foreach (DirectoryInfo currentDir in directoryDIRArray)
{
// 遞迴呼叫方法,找到檔案,則使用 AssetImporter 類,標記“包名”與 “字尾名”
JudgeDirOrFileByRecursive(currentDir);
}
// 清空無用的 AB 標記
AssetDatabase.RemoveUnusedAssetBundleNames();
// 重新整理
AssetDatabase.Refresh();
// 提示資訊,標記包名完成
Debug.Log("AssetBundle 本次操作移除標記完成");
}
/// <summary>
/// 遞迴判斷判斷是否是目錄或檔案
/// 是檔案,修改 Asset Bundle 標記
/// 是目錄,則繼續遞迴
/// </summary>
/// <param name="fileSystemInfo">當前檔案資訊(檔案資訊與目錄資訊可以相互轉換)</param>
private static void JudgeDirOrFileByRecursive(FileSystemInfo fileSystemInfo)
{
// 引數檢查
if (fileSystemInfo.Exists == false)
{
Debug.LogError("檔案或者目錄名稱:" + fileSystemInfo + " 不存在,請檢查");
return;
}
// 得到當前目錄下一級的檔案資訊集合
DirectoryInfo directoryInfoObj = fileSystemInfo as DirectoryInfo;
// 檔案資訊轉為目錄資訊
FileSystemInfo[] fileSystemInfoArray = directoryInfoObj.GetFileSystemInfos();
foreach (FileSystemInfo fileInfo in fileSystemInfoArray)
{
FileInfo fileInfoObj = fileInfo as FileInfo;
// 檔案型別
if (fileInfoObj != null)
{
// 修改此檔案的 AssetBundle 標籤
RemoveFileABLabel(fileInfoObj);
}
// 目錄型別
else
{
// 如果是目錄,則遞迴呼叫
JudgeDirOrFileByRecursive(fileInfo);
}
}
}
/// <summary>
/// 給檔案移除 Asset Bundle 標記
/// </summary>
/// <param name="fileInfoObj">檔案(檔案資訊)</param>
static void RemoveFileABLabel(FileInfo fileInfoObj)
{
// AssetBundle 包名稱
string strABName = string.Empty;
// 檔案路徑(相對路徑)
string strAssetFilePath = string.Empty;
// 引數檢查(*.meta 檔案不做處理)
if (fileInfoObj.Extension == ".meta")
{
return;
}
// 得到 AB 包名稱
strABName = string.Empty;
// 獲取資原始檔的相對路徑
int tmpIndex = fileInfoObj.FullName.IndexOf("Assets");
// 得到檔案相對路徑
strAssetFilePath = fileInfoObj.FullName.Substring(tmpIndex);
// 給資原始檔移除 AB 名稱
AssetImporter tmpImportObj = AssetImporter.GetAtPath(strAssetFilePath);
tmpImportObj.assetBundleName = strABName;
}
}
4.擴充
更多的時候,我們打包需要一鍵打包,也可能需要多個檔案打成一個ab包,只需要修改一下檔案邏輯即可;
打ab包本身並不複雜,對檔案路徑字串的處理比較多,多Debug除錯;