目录
前言
本篇文章是整个打包的核心,我们需要告诉打包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
还有一点非常重要,ab包的名字除了可以使用字符串,还可以使用MD5码
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);
}
}