前言
本篇文章是整個打包的核心,我們需要告訴打包API打包目标是什麼,在整理目标的時候,可以定制化各種各樣的收集政策,以及剔除政策、引用政策等。
正文開始
首先要明确,我們的最終目标是收集打包資源。但請注意,該步驟收集的不是最終調用打包接口的參數2。而是包含了我們自己自己需要的一些資訊,當然,其中包含了參數2需要的資訊。
AssetBundleManifest.BuildAssetBundles(string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform);
下面是收集資源的代碼,非常重要!!!仔細看,多看,該方法的傳回值是List<AssetInfo>
private List<AssetInfo> GetBuildMap()
{
int progressBarCount = 0;
Dictionary<string, AssetInfo> allAsset = new Dictionary<string, AssetInfo>();
// 擷取所有的收集路徑,該方法在上一篇文章裡有代碼
List<string> collectPathList = CollectionSettingData.GetAllCollectPath();
if (collectPathList.Count == 0)
throw new Exception("[BuildPatch] 配置的打包路徑清單為空");
// 擷取所有資源
string[] guids = AssetDatabase.FindAssets(string.Empty, collectPathList.ToArray());
foreach (string guid in guids)
{
string mainAssetPath = AssetDatabase.GUIDToAssetPath(guid);
if (CollectionSettingData.IsIgnoreAsset(mainAssetPath))
continue;
if (ValidateAsset(mainAssetPath) == false)
continue;
List<AssetInfo> depends = GetDependencies(mainAssetPath);
for (int i = 0; i < depends.Count; i++)
{
AssetInfo assetInfo = depends[i];
if (assetInfo.AssetPath.Contains("Activity.RU"))
{
throw new Exception($"[BuildPatch] Contain: {assetInfo.AssetPath} by {mainAssetPath}");
}
if (allAsset.ContainsKey(assetInfo.AssetPath))
{
AssetInfo cacheInfo = allAsset[assetInfo.AssetPath];
cacheInfo.DependCount++;
}
else
{
allAsset.Add(assetInfo.AssetPath, assetInfo);
}
}
// 進度條
progressBarCount++;
EditorUtility.DisplayProgressBar("進度", $"依賴檔案分析:{progressBarCount}/{guids.Length}", (float)progressBarCount / guids.Length);
}
EditorUtility.ClearProgressBar();
progressBarCount = 0;
// 移除零依賴的資源
List<string> removeList = new List<string>();
foreach (KeyValuePair<string, AssetInfo> pair in allAsset)
{
if (pair.Value.IsCollectAsset)
continue;
if (pair.Value.DependCount == 0)
removeList.Add(pair.Value.AssetPath);
else if (pair.Value.AssetPath.ToLower().Contains("assets/worksart/panel/atlas/"))
removeList.Add(pair.Value.AssetPath);
}
for (int i = 0; i < removeList.Count; i++)
{
allAsset.Remove(removeList[i]);
}
// 設定AssetBundleLabel資源标簽
foreach (KeyValuePair<string, AssetInfo> pair in allAsset)
{
SetAssetBundleLabelAndVariant(pair.Value);
SetAssetEncrypt(pair.Value);
// 進度條
progressBarCount++;
EditorUtility.DisplayProgressBar("進度", $"設定資源标簽:{progressBarCount}/{allAsset.Count}", (float)progressBarCount / allAsset.Count);
}
EditorUtility.ClearProgressBar();
progressBarCount = 0;
// Dictionary<string, long> dicSortedBySize = allAsset.OrderBy(o => o.Value.sizeKB).ToDictionary(p => p.Key, o => o.Value.sizeKB);
// foreach (KeyValuePair<string, long> pair in dicSortedBySize)
// {
// Log($"AB asset: {pair.Key}, sizeKB: {pair.Value}");
// }
// 傳回結果
return allAsset.Values.ToList();
}
下面是擷取所有依賴的方法
private List<AssetInfo> GetDependencies(string assetPath)
{
List<AssetInfo> depends = new List<AssetInfo>();
string[] dependArray = AssetDatabase.GetDependencies(assetPath, true);
foreach (string dependPath in dependArray)
{
if (ValidateAsset(dependPath))
{
AssetInfo assetInfo = new AssetInfo(dependPath);
depends.Add(assetInfo);
}
}
return depends;
}
下面是設定AssetBundleLabel的方法,請注意,CollectionSettingData.GetAssetBundleLabel在上一篇文章中有代碼
variant變量就是ab包的字尾,一般.unity3d
private void SetAssetBundleLabelAndVariant(AssetInfo assetInfo)
{
string label = CollectionSettingData.GetAssetBundleLabel(assetInfo.AssetPath);
string variant = VariantCollector.GetVariantByAssetPath(label);
if (string.IsNullOrEmpty(variant))
{
variant = PatchDefine.AssetBundleDefaultVariant;
}
else
{
label = label.Replace(variant, "");
variant = variant.Substring(1);
}
if (IsNameByHash)
assetInfo.AssetBundleLabel = HashUtility.BytesMD5(Encoding.UTF8.GetBytes(label));
else
assetInfo.AssetBundleLabel = label;
assetInfo.ReadableLabel = label;
assetInfo.AssetBundleVariant = variant;
assetInfo.bundlePos = CollectionSettingData.GetAssetBundlePos(assetInfo.AssetPath);
// assetInfo.sizeKB = EditorTools.GetFileSize(assetInfo.AssetPath);
}
下面是AssetInfo的代碼
public class AssetInfo
{
public string AssetPath { private set; get; }
public bool IsCollectAsset { private set; get; }
public bool IsSceneAsset { private set; get; }
public bool IsVideoAsset { private set; get; }
/// <summary>
/// 被依賴次數
/// </summary>
public int DependCount = 0;
/// <summary>
/// AssetBundle标簽
/// </summary>
public string AssetBundleLabel = null;
/// <summary>
/// AssetBundle變體
/// </summary>
public string AssetBundleVariant = null;
/// <summary>
/// AssetBundle存放位置
/// </summary>
public EBundlePos bundlePos = EBundlePos.buildin;
public string ReadableLabel = "undefined";
public EEncryptMethod EncryptMethod;
public AssetInfo(string assetPath)
{
AssetPath = assetPath;
IsCollectAsset = CollectionSettingData.IsCollectAsset(assetPath);
IsSceneAsset = AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(SceneAsset);
IsVideoAsset = AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(UnityEngine.Video.VideoClip);
}
}