引言:
上一篇文章介绍了,利用System.IO的接口,收集路径下所有文件夹的方式设置asset bundle name,这一次介绍另一种方法。
原理:
经同事提醒,发现Unity有原生的资源管理器AssetPostprocessor,官方描述:AssetPostprocessor lets you hook into the import pipeline and run scripts prior or after importing assets.
其内部提供了很多接口,本次要用到的是OnPostprocessAllAssets,官方描述:This is called after importing of any number of assets is complete (when the Assets progress bar has reached the end).
上一篇文章,收集asset bundle name需要在打包之前,手动执行脚本;而OnPostprocessAllAssets会在每次资源的增删改后自动执行,那么就有了自动设置asset bundle name的进阶版。
官方样例:
现将官方示例输入,查看输出情况:
using UnityEngine;
using System.Collections;
using UnityEditor;
public class AutoGenerateAssetBundleNameImproved : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
for (int i = 0; i < importedAssets.Length; ++i)
{
Debug.Log("Imported asset: " + importedAssets[i]);
}
for (int i = 0; i < deletedAssets.Length; ++i)
{
Debug.Log("Deleted asset: " + deletedAssets[i]);
}
for (int i = 0; i < movedAssets.Length; ++i)
{
Debug.Log("Moved Asset: " + movedAssets[i] + " ---- From: " + movedFromAssetPaths[i]);
}
}
}
在Assets/路径下增删改资源做测试,新建两个测试文件夹Assets/Demo/Resources/PathA,Assets/Demo/Resources/PathB:
分别添加,移动和删除一张测试用的图片资源:
输出结果如下:
考虑到文件移动可能会出现移动文件夹的情况,需要多做一个测试,移动下面文件夹:
从当前路径移动到PathB路径下
可以看到会遍历文件夹 下的3个文件,不过最后文件夹自己也触发了移动move asset,需要人为进行排除。
此处应该有代码:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class AutoGenerateAssetBundleNameImproved : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
for (int i = 0; i < importedAssets.Length; ++i)
{
Debug.Log("Imported asset: " + importedAssets[i]);
UpdateAssetBundleName(importedAssets[i]);
}
for (int i = 0; i < deletedAssets.Length; ++i)
{
Debug.Log("Deleted asset: " + deletedAssets[i]);
// 当删除的文件是命名为当前asset bundle name的最后一个文件时,移除asset bundle name
AssetDatabase.RemoveUnusedAssetBundleNames();
AssetDatabase.Refresh();
}
for (int i = 0; i < movedAssets.Length; ++i)
{
Debug.Log("Moved Asset: " + movedAssets[i] + " ---- From: " + movedFromAssetPaths[i]);
UpdateAssetBundleName(movedAssets[i]);
}
}
static void UpdateAssetBundleName(string filePath)
{
// 当filePath的输入为.meta文件时,调用AssetImporter.GetAtPath会报错。
if (IsBlockedByExtension(filePath))
{
Debug.Log("UpdateAssetBundleName IsBlockedByExtension: " + filePath);
return;
}
AssetImporter importer = AssetImporter.GetAtPath(filePath);
if (importer != null)
{
if (IsBlockedByDirectories(filePath))
{
Debug.Log("UpdateAssetBundleName IsBlockedByDirectories: " + filePath);
importer.assetBundleName = "";
return;
}
if (IsBlockedByBlackList(filePath))
{
Debug.Log("UpdateAssetBundleName IsBlockedByBlackList: " + filePath);
importer.assetBundleName = "";
return;
}
int position = filePath.LastIndexOf(@"/");
string assetBundlePath = filePath.Substring(0, position);
importer.assetBundleName = assetBundlePath.Replace('/', '_');
importer.assetBundleVariant = "";
Debug.Log("UpdateAssetBundleName assetBundleName: " + importer.assetBundleName);
}
}
// 黑名单关键字列表,遍历文件夹时忽略
static public string[] skip_dirs_all = { "testBlackList" };
/// <summary>
/// 判断是否被黑名单文件夹列表过滤
/// </summary>
static bool IsBlockedByBlackList(string filePath)
{
List<string> PathblackList = new List<string>(skip_dirs_all);
string[] folderNames = filePath.Split('/');
foreach (string path in PathblackList)
{
for (int i = 0; i < folderNames.Length; ++i)
{
if (string.Compare(path, folderNames[i], true) == 0)
return true;
}
}
return false;
}
// 黑名单后缀名列表,遍历文件夹时忽略
static public string[] skip_extensions_all = { ".cs", ".meta" };
/// <summary>
/// 判断是否被黑名单后缀名列表过滤
/// </summary>
static bool IsBlockedByExtension(string filePath)
{
List<string> ExtBlackList = new List<string>(skip_extensions_all);
string extension = Path.GetExtension(filePath);
foreach(string ext in ExtBlackList)
{
if (string.Compare(extension.ToLower(), ext, true) == 0)
return true;
}
return false;
}
/// <summary>
/// 判断是否为文件夹
/// </summary>
static bool IsBlockedByDirectories(string filePath)
{
return Directory.Exists(filePath);
}
}
再次测试将图片添加到PathA,移动到PathB
,删除图片运行结果如下:
添加到PathA时,asset bundle name:
移动到PathB时,asset bundle name:
小结:
本次介绍的方法可以实现真正自动设置asset bundle name,而无需手动运行脚本。利用AssetPostprocessor的其他接口可以实现更多特殊的自动化处理,比如利用OnPostprocessTexture、OnPreprocessTexture可以在导入贴图资源时,按照项目规范自动修改贴图属性。