Unity杂文——AssetBundle自动标记

  1. 目的
  2. 思路
  3. 一键打包
  4. 一键删除

原文地址

参考文章

目的

当我们想把资源打包成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

×

喜欢就点赞,疼爱就打赏