目的
当我们想把资源打包成AB的时候,需要把资源一个一个标记AB名字,其实大多数名字都是资源名字,如果资源一旦很多,就需要花费大量的时间,为了提高开发效率,我们肯定希望能把需要热更的资源一键标记资源名字。
思路
自动打标记无非就是给我一个资源路径,我通过这个路径将里面的所有的资源文件遍历一遍,然后通过 AssetImporter 这个 API 设置每个文件的 assetbundleName 和 assetBundleVariant 属性,当然在设置属性的时候提前分好类,决定将哪些资源放到一个 AssetBundle 包内。然后记录一下要打多少个 AssetBundle 包,以及该包所在的目录,方便以后查找加载。
废话不多说,直接上代码:
# region 自动做标记
[MenuItem("AssetBundle/Set AssetBundle Lables" ,false , 100)]
public static void SetAssetBundleLables()
{
//移除掉所有没有使用的标记
AssetDatabase.RemoveUnusedAssetBundleNames();
string assetDirectory = "Assets/Res";
DirectoryInfo directoryInfo = new DirectoryInfo(assetDirectory);
DirectoryInfo[] scenesDirectories = directoryInfo.GetDirectories();
foreach (var tempDir in scenesDirectories)
{
string sceneDirectory = assetDirectory + "/" + tempDir.Name;
DirectoryInfo sceneDirectoryInfo = new DirectoryInfo(sceneDirectory);
if (sceneDirectoryInfo == null)
{
Debug.Log(sceneDirectoryInfo + "不存在");
return;
}
else
{
Dictionary<string , string> namePathDictionary = new Dictionary<string, string>();
int index = sceneDirectory.LastIndexOf("/");
string sceneName = sceneDirectory.Substring(index + 1);
OnSceneFileSystemInfo(sceneDirectoryInfo , sceneName , namePathDictionary);
OnWriteConfig(sceneName , namePathDictionary);
}
}
AssetDatabase.Refresh();
Debug.Log("设置标记成功...");
}
/// <summary>
/// 记录配置文件
/// </summary>
/// <param name="sceneDirectory"></param>
/// <param name="namePathDictionary"></param>
private static void OnWriteConfig(string sceneName , Dictionary<string , string> namePathDictionary)
{
string path = Application.dataPath + "/AssetBundles/" + sceneName ;
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
Debug.Log(path);
using (FileStream fs = new FileStream(path + "/Record.txt", FileMode.OpenOrCreate , FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(namePathDictionary.Count);
foreach (KeyValuePair<string , string> kv in namePathDictionary)
{
Debug.Log(kv.Value);
sw.WriteLine(kv.Key+"/"+kv.Value);
}
}
}
}
private static void OnSceneFileSystemInfo(FileSystemInfo fileSystemInfo , string sceneNama , Dictionary<string, string> namePathDictionary)
{
if (!fileSystemInfo.Exists)
{
Debug.Log(fileSystemInfo + "不存在");
return;
}
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
foreach (var systemInfo in fileSystemInfos)
{
FileInfo fileInfo = systemInfo as FileInfo;
if (fileInfo == null)
{
OnSceneFileSystemInfo(systemInfo, sceneNama , namePathDictionary);
}
else
{
SetLables(fileInfo, sceneNama , namePathDictionary);
}
}
}
/// <summary>
/// 修改资源 assetbundle lables
/// </summary>
private static void SetLables(FileInfo fileInfo , string sceneName , Dictionary<string, string> namePathDictionary)
{
if(fileInfo.Extension == ".meta")return;
string bundleName = GetBundleName(fileInfo , sceneName);
int index = fileInfo.FullName.IndexOf("Assets");
string assetPath = fileInfo.FullName.Substring(index);
AssetImporter assetImporter = AssetImporter.GetAtPath(assetPath);
assetImporter.assetBundleName = bundleName;
if (fileInfo.Extension == ".unity")
assetImporter.assetBundleVariant = "u3d";
else
assetImporter.assetBundleVariant = "assetbundle";
string folderName;
if (bundleName.Contains("/"))
folderName = bundleName.Split('/')[1];
else
folderName = bundleName;
string bundlePath = assetImporter.assetBundleName + "." + assetImporter.assetBundleVariant;
if (!namePathDictionary.ContainsKey(folderName))
namePathDictionary.Add(folderName, bundlePath);
}
private static string GetBundleName(FileInfo fileInfo, string sceneName)
{
string path = fileInfo.FullName;
int index = path.IndexOf(sceneName) + sceneName.Length;
string bundlePath = path.Substring(index + 1);
bundlePath = bundlePath.Replace(@"\", "/");
if (bundlePath.Contains("/"))
{
string[] tmp = bundlePath.Split('/');
return sceneName + "/" + tmp[0];
}
return sceneName;
}
#endregion
一键打包
一键打包
根据刚才我们设置好的标记,Unity 就可以识别到我们想要打包的资源,官方有个打包 AssetBundle 的插件( AssetBundle Browser ),你可以用那款插件打包。
作自己也写了一个但是不是很好,这个东西可以用官方的代替。也可以根据自己的需求改一下。我这里选择的压缩方式是不压缩( BuildAssetBundleOptions.None 这个选项)。
#region 打包
static void BuildAssetBundles(string outPath , BuildTarget target)
{
if (!Directory.Exists(outPath)) Directory.CreateDirectory(outPath);
BuildPipeline.BuildAssetBundles(outPath, BuildAssetBundleOptions.None, target);
}
[MenuItem("AssetBundle/CreateAndroidAssetBundles", false, 200)]
public static void BuildAndroidAssetBundles()
{
string outPath = "Assets/AssetBundles/Android";
BuildAssetBundles(outPath , BuildTarget.Android);
}
[MenuItem("AssetBundle/CreateIOSAssetBundles", false, 201)]
public static void BuildIOSAssetBundles()
{
string outPath = "Assets/AssetBundles/IOS";
BuildAssetBundles(outPath, BuildTarget.iOS);
}
[MenuItem("AssetBundle/CreateStandaloneWindows64AssetBundles", false, 202)]
public static void BuildStandaloneWindows64AssetBundles()
{
string outPath = "Assets/AssetBundles/StandaloneWindows64";
BuildAssetBundles(outPath, BuildTarget.StandaloneWindows64);
}
#endregion
一键删除
把目标路径删除掉就 OK 了。
#region 一键删除
[MenuItem("AssetBundle/Delete All")]
static void DeletAssetBundles()
{
string outPuth = "Assets/AssetBundles";
Directory .Delete(outPuth , true);
File.Delete(outPuth+ ".meta");
AssetDatabase.Refresh();
}
#endregion
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 841774407@qq.com