unity打包脚本

打包界面参考的https://github.com/Unity-Technologies/AssetBundles-Browser,逻辑等都是自己写的

上代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;


namespace AssetBundleBrowser
{
    public class BuildPacker
    {
        private BuildTargetType targetContent = BuildTargetType.Android;
        private string outputPath = "Assets/StreamingAssets";
        private int compressionOption = 1;
        private string rewRootPath = "Assets/SubAssets/Rew";
        private string resRootPath = "Assets/SubAssets/Res";
        [SerializeField]
        internal AssetBundleManageTab m_ManageTab;
        private List<AssetBundleBuild> buildList = new List<AssetBundleBuild>();
        private List<string> bundleLabelPathList = new List<string>();
        private static string filePath = string.Empty;
        private bool isRebuild = false;
        private EditorWindow parentWindow;

        internal enum BuildTargetType
        {
            MacOS = 2,
            iOS = 9,
            Android = 13,
            Windows = 19,
        }

        internal enum CompressOptions
        {
            Uncompressed = 1,
            LZMA = 0,
            LZ4 = 256,
        }

        GUIContent[] compressionOptions =
            {
            new GUIContent("No Compression"),
            new GUIContent("LZMA"),
            new GUIContent("LZ4")
        };

        int[] compressionValues = { 1, 0, 256 };

        internal void OnEnable(EditorWindow parent)
        {
            parentWindow = parent;
            filePath = Application.dataPath + "/SubAssets/Scripts/GameEditor/Editor/bundleName.txt";
        }

        internal void OnDisable()
        {

        }

        internal void OnGUI()
        {
            EditorGUILayout.Space();
            GUILayout.BeginVertical();
            // 构建平台
            targetContent = (BuildTargetType)EditorGUILayout.EnumPopup(new GUIContent("Build Target"), targetContent);
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            // bundle生成路径
            outputPath = EditorGUILayout.TextField("Output Path", outputPath);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            // 修改bundle生成路径
            if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
                BrowseForFolder();
            // bungle生成路径复位
            if (GUILayout.Button("Reset", GUILayout.MaxWidth(75f)))
                ResetPathToDefault();

            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.Space();
            // bundle压缩选择
            compressionOption = EditorGUILayout.IntPopup(new GUIContent("CompressOption"),
                compressionOption,
                compressionOptions,
                compressionValues);

            EditorGUILayout.Space();
            // 是否重置bundle标签
            isRebuild = EditorGUILayout.Toggle("重置bundle标签", isRebuild);

            EditorGUILayout.Space();
            // build.
            EditorGUILayout.Space();
            if (GUILayout.Button("Build"))
            {
                EditorApplication.delayCall += ExecuteBuild;
            }
            GUILayout.EndVertical();
        }

        private void BrowseForFolder()
        {
            var newPath = EditorUtility.OpenFolderPanel("Bundle Folder", outputPath, string.Empty);
            if (!string.IsNullOrEmpty(newPath))
            {
                outputPath = newPath;
            }
        }

        private void ResetPathToDefault()
        {
            outputPath = "Assets/StreamingAssets";
        }

        private void ExecuteBuild()
        {
            buildList.Clear();

            if ((int)EditorUserBuildSettings.activeBuildTarget != (int)targetContent)
            {
                if (!SwitchPlatform())
                {
                    Debug.LogError("切换平台失败!");
                    return;
                }
            }

            CompressAtlas();
            CompressTexture();

            if (Directory.Exists(outputPath))
                DelectDir();
            if (!Directory.Exists(outputPath))
                Directory.CreateDirectory(outputPath);

            if (isRebuild) ClearBundleFileName();
            Building();
            WriteFile();
            BuildFileIndex();
            AssetDatabase.Refresh();
            if (parentWindow != null) parentWindow.Close();
            Debug.Log("打包完成!");
        }

        private void DelectDir()
        {
            string withoutExtensions = ".meta";
            string[] filePaths = Directory.GetFiles(outputPath);
            for (int i = 0; i < filePaths.Length; i++)
            {
                string path = filePaths[i];
                if (path.Contains(withoutExtensions)) continue;
                FileUtil.DeleteFileOrDirectory(path);
            }
        }

        private void WriteFile()
        {
            if (bundleLabelPathList.Count > 0)
            {
                File.WriteAllLines(filePath, bundleLabelPathList.ToArray(), Encoding.UTF8);
            }
        }

        private void ClearBundleFileName()
        {
            if (!File.Exists(filePath)) return;
            string[] lines = File.ReadAllLines(filePath);
            for (int i = 0; i < lines.Length; i++)
            {
                AssetImporter import = AssetImporter.GetAtPath(lines[i]);
                import.assetBundleName = string.Empty;
                if (!string.IsNullOrEmpty(import.assetBundleVariant))
                    import.assetBundleVariant = string.Empty;
            }
        }

        /// <summary>
        /// 构建bundle
        /// </summary>
        private void Building()
        {
            BuildAssetBundle();
            int target = (int)targetContent;
            BuildPipeline.BuildAssetBundles(outputPath, buildList.ToArray(), (BuildAssetBundleOptions)compressionOption, (BuildTarget)target);
        }

        /// <summary>
        /// 设置bundle标签
        /// </summary>
        private void BuildAssetBundle()
        {
            BuildRewBundle();
            BuildResBundle();
        }

        /// <summary>
        /// 给Rew文件夹下所有文件设置bundle标签
        /// </summary>
        private void BuildRewBundle()
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(rewRootPath);
            DirectoryInfo[] rewDirectories = directoryInfo.GetDirectories();
            for (int i = 0; i < rewDirectories.Length; i++)
            {
                DirectoryInfo info = rewDirectories[i];
                string infoName = info.Name;
                if (infoName.Equals("ui") || infoName.Equals("Scenes"))
                    continue;
                else if (infoName.Equals("shaders")) BuildRewShadersBundle(info);
                else if (infoName.Equals("Effects")) BuildRewEffectsBundle(info);
                else if (infoName.Equals("Character")) BuildRewCharacterBundle(info);
            }
        }

        /// <summary>
        /// 给rew文件夹下Character文件夹下文件设置bundle标签
        /// </summary>
        /// <param name="info">Character文件夹实例</param>
        private void BuildRewCharacterBundle(DirectoryInfo info)
        {
            DirectoryInfo[] dirs = info.GetDirectories();
            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                if (dir.Name.Equals("Animations"))
                {
                    string bundleName = GetAnimationsDirBundleName(dir);
                    BuildBundle(bundleName, dir);
                }
                else
                {
                    BuildRewCharacterBundle(dir);
                }
            }
        }

        /// <summary>
        /// 获取Animations文件夹的bundle名
        /// </summary>
        /// <param name="dir"></param>
        private string GetAnimationsDirBundleName(DirectoryInfo dir)
        {
            string sprChar = "\\";
#if UNITY_EDITOR_OSX
        sprChar = "/";
#endif
            string fullName = dir.FullName;
            string preStr = "";
            string tempStr = "";
            while (true)
            {
                tempStr = fullName.Substring(fullName.LastIndexOf(sprChar) + 1);
                if (tempStr.Equals("Character")) break;
                fullName = fullName.Substring(0, fullName.LastIndexOf(sprChar));
                if (string.IsNullOrEmpty(preStr))
                {
                    preStr = string.Format("{0}{1}", preStr, tempStr);
                }
                else
                {
                    preStr = string.Format("{0}_{1}", preStr, tempStr);
                }
            }
            return preStr;
        }

        /// <summary>
        /// rew文件夹下Effects文件夹下文件设置bundle标签
        /// </summary>
        /// <param name="info">Effects文件夹实例</param>
        private void BuildRewEffectsBundle(DirectoryInfo info)
        {
            DirectoryInfo[] dirInfos = info.GetDirectories();
            for (int i = 0; i < dirInfos.Length; i++)
            {
                DirectoryInfo dirInfo = dirInfos[i];
                if (dirInfo.Name.Equals("Base"))
                {
                    DirectoryInfo[] baseDirs = dirInfo.GetDirectories();
                    for (int j = 0; j < baseDirs.Length; j++)
                    {
                        DirectoryInfo temp = baseDirs[j];
                        BuildBundle(temp.Name, temp, "eff_base");
                    }
                    
                    BuildBundle(dirInfo, "eff_base");
                }
                else if (dirInfo.Name.Equals("Models"))
                {
                    DirectoryInfo[] baseDirs = dirInfo.GetDirectories();
                    for (int j = 0; j < baseDirs.Length; j++)
                    {
                        DirectoryInfo molInfo = baseDirs[j];
                        if (molInfo.Name.Equals("Materials"))
                        {
                            BuildBundle(molInfo, "eff_models");
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 文件夹内所有文件构成一个bundle
        /// </summary>
        /// <param name="bunleName">bundle名称</param>
        /// <param name="info">文件夹实例</param>
        /// <param name="prefix">前缀</param>
        private void BuildBundle(string bunleName, DirectoryInfo info, string prefix = null)
        {
            FileInfo[] fs = info.GetFiles();
            List<string> assetNames = new List<string>();
            AssetBundleBuild build = new AssetBundleBuild();
            if (prefix != null)
            {
                bunleName = string.Format("{0}_{1}", prefix, bunleName);
            }
            build.assetBundleName = bunleName.ToLower();
            for (int i = 0; i < fs.Length; i++)
            {
                FileInfo f = fs[i];
                if (f.Extension == ".meta")
                    continue;
                string path = f.FullName;
                string assetName = path.Substring(path.IndexOf("Assets"));
                assetNames.Add(assetName);
            }
            build.assetNames = assetNames.ToArray();
            buildList.Add(build);

            //用 AssetImporter 类 修改名称和后缀
            string dirPath = info.FullName.Substring(info.FullName.IndexOf("Assets"));
            AssetImporter assetImporter = AssetImporter.GetAtPath(dirPath);
            assetImporter.assetBundleName = bunleName.ToLower();
            assetImporter.SaveAndReimport();
        }

        /// <summary>
        /// 此文件设置为单个bundle
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="info">文件实例</param>
        private void BuildBundle(string fileName, FileInfo info)
        {
            AssetBundleBuild build = new AssetBundleBuild();
            string bundleName = fileName.Split(new char[] { '.' })[0];
            string path = info.FullName;
            string assetName = path.Substring(path.IndexOf("Assets"));
            build.assetNames = new string[] { assetName };
            build.assetBundleName = bundleName.ToLower();
            buildList.Add(build);

            //用 AssetImporter 类 修改名称和后缀
            AssetImporter assetImporter = AssetImporter.GetAtPath(assetName);
            assetImporter.assetBundleName = bundleName.ToLower();
            assetImporter.SaveAndReimport();

        }

        /// <summary>
        /// 文件夹内的每个文件都是一个bundle
        /// </summary>
        /// <param name="info">文件夹实例</param>
        /// <param name="prefix">前缀</param>
        private void BuildBundle(DirectoryInfo info, string prefix = null)
        {
            FileInfo[] infos = info.GetFiles();
            for (int i = 0; i < infos.Length; i++)
            {
                FileInfo fileInfo = infos[i];
                //忽视unity自身生成的meta文件
                if (fileInfo.Extension == ".meta")
                    continue;
                string bunleName = fileInfo.Name;
                if (prefix != null)
                {
                    bunleName = string.Format("{0}_{1}", prefix, bunleName);
                }
                BuildBundle(bunleName, fileInfo);
            }
        }

        /// <summary>
        /// 设置rew文件夹下Shaders文件夹下文件的bundle标签
        /// </summary>
        /// <param name="info">Shaders文件夹实例</param>
        private void BuildRewShadersBundle(DirectoryInfo info)
        {
            BuildBundle(info);
        }

        /// <summary>
        /// 给Res文件夹下所有文件设置bundle标签
        /// </summary>
        private void BuildResBundle()
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(resRootPath);
            DirectoryInfo[] resDirectories = directoryInfo.GetDirectories();
            int dirCount = resDirectories.Length;
            for (int i = 0; i < dirCount; i++)
            {
                DirectoryInfo info = resDirectories[i];
                string dirName = info.Name;
                if (dirName.Equals("Splat")) BuildResSplatBundle(info);
            }

            for (int i = 0; i < dirCount; i++)
            {
                DirectoryInfo info = resDirectories[i];
                string dirName = info.Name;
                if (dirName.Equals("Prefabs")) BuildResPrefabBundle(info);
            }

            for (int i = 0; i < dirCount; i++)
            {
                DirectoryInfo info = resDirectories[i];
                string dirName = info.Name;
                if (dirName.Equals("ReaderTexture")) BuildResRTBundle(info);
            }

            for (int i = 0; i < dirCount; i++)
            {
                DirectoryInfo info = resDirectories[i];
                string dirName = info.Name;
                if (dirName.Equals("Scenes")) BuildResSceneBundle(info);
            }
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildResPrefabBundle(DirectoryInfo info)
        {
            DirectoryInfo[] dirs = info.GetDirectories();
            int dirCount = dirs.Length;
            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("Bullet")) BuildPrefabBullet(dir);
            }

            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("Effects")) BuildPrefabEffect(dir);
            }

            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("character")) BuildPrefabCharacter(dir);
            }

            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("UI")) BuildPrefabUI(dir);
            }

            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("Scenes")) BuildPrefabScenes(dir);
            }
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下Scenes文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildPrefabScenes(DirectoryInfo dir)
        {
            DirectoryInfo[] dirInfos = dir.GetDirectories();
            for (int j = 0; j < dirInfos.Length; j++)
            {
                DirectoryInfo dirInfo = dirInfos[j];
                BuildBundle(dirInfo.Name, dirInfo);
            }
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下Bullet文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildPrefabBullet(DirectoryInfo info)
        {
            BuildBundle(info);
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下character文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildPrefabCharacter(DirectoryInfo info)
        {
            // 暂时先直接处理,后面要分成种族等文件夹之后再处理
            BuildBundle(info);
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下Effects文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildPrefabEffect(DirectoryInfo info)
        {
            BuildBundle(info);
        }

        /// <summary>
        /// 设置Res文件夹下Prefabs文件夹下UI文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildPrefabUI(DirectoryInfo info)
        {
            // UI现在还差一个公共图集的文件夹
            DirectoryInfo[] dirs = info.GetDirectories();
            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                string dirName = dir.Name;
                if (dirName.Equals("UIRoot"))
                {
                    BuildBundle(dir);
                }
                else if (dirName.Equals("UITemplate"))
                {
                    continue;
                }
                else if (dirName.Equals("UIView"))
                {
                    DirectoryInfo[] dirInfos = dir.GetDirectories();
                    for (int j = 0; j < dirInfos.Length; j++)
                    {
                        DirectoryInfo dirInfo = dirInfos[j];
                        BuildBundle(dirInfo.Name, dirInfo);
                    }
                }
            }
        }

        /// <summary>
        /// 设置Res文件夹下RenderTexture文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildResRTBundle(DirectoryInfo info)
        {
            BuildBundle(info, "RT");
        }

        /// <summary>
        /// 设置Res文件夹下Scenes文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildResSceneBundle(DirectoryInfo info)
        {
            // 场景打包暂时这样处理,后面要把场景分割通过配置文件对位置
            DirectoryInfo[] dirs = info.GetDirectories();
            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                DirectoryInfo[] dirInfos = dir.GetDirectories();
                for (int j = 0; j < dirInfos.Length; j++)
                {
                    DirectoryInfo dirInfo = dirInfos[j];
                    BuildSceneLightMap(dirInfo);
                }
                BuildBundle(dir, "scene");
            }
        }

        /// <summary>
        /// lightMap文件夹比较特殊,要把LightingData.asset文件剔除
        /// </summary>
        /// <param name="dirInfo"></param>
        private void BuildSceneLightMap(DirectoryInfo dirInfo)
        {
            FileInfo[] infos = dirInfo.GetFiles();
            List<string> assetNames = new List<string>();
            AssetBundleBuild build = new AssetBundleBuild();
            build.assetBundleName = dirInfo.Name.ToLower();
            for (int i = 0; i < infos.Length; i++)
            {
                FileInfo fileInfo = infos[i];
                //忽视unity自身生成的meta文件
                if (fileInfo.Extension == ".meta" || fileInfo.Extension == ".asset")
                    continue;
                string path = fileInfo.FullName;
                string assetName = path.Substring(path.IndexOf("Assets"));
                assetNames.Add(assetName);

                //用 AssetImporter 类 修改名称和后缀
                AssetImporter assetImporter = AssetImporter.GetAtPath(assetName);
                assetImporter.assetBundleName = dirInfo.Name.ToLower();
                assetImporter.SaveAndReimport();
            }
            build.assetNames = assetNames.ToArray();
            buildList.Add(build);
        }

        /// <summary>
        /// 设置Res文件夹下Splat文件夹下文件bundle标签
        /// </summary>
        /// <param name="info"></param>
        private void BuildResSplatBundle(DirectoryInfo info)
        {
            DirectoryInfo[] dirs = info.GetDirectories();
            for (int i = 0; i < dirs.Length; i++)
            {
                DirectoryInfo dir = dirs[i];
                BuildBundle(dir.Name, dir, "Splat");
            }
            BuildBundle(info, "Splat");
        }

        /// <summary>
        /// 切换平台
        /// </summary>
        /// <returns></returns>
        private bool SwitchPlatform()
        {
            int target = (int)targetContent;
            BuildTargetGroup group = BuildTargetGroup.Standalone;
            switch (targetContent)
            {
                case BuildTargetType.iOS:
                    group = BuildTargetGroup.iOS;
                    break;
                case BuildTargetType.Android:
                    group = BuildTargetGroup.Android;
                    break;
                default:
                    break;
            }
            return EditorUserBuildSettings.SwitchActiveBuildTarget(group, (BuildTarget)target);
        }

        /// <summary>
        /// 压缩贴图
        /// </summary>
        private void CompressTexture()
        {
            Debug.Log("压缩贴图!");
        }

        /// <summary>
        /// 压缩图集
        /// </summary>
        private void CompressAtlas()
        {
            Debug.Log("压缩图集!");
        }
        
        private void BuildFileIndex() {
        ///----------------------创建文件列表-----------------------
            string newFilePath = outputPath + "/files.txt";
            if (File.Exists(newFilePath)) File.Delete(newFilePath);
            
            List<string> files = Recursive(outputPath);

            FileStream fs = new FileStream(newFilePath, FileMode.CreateNew);
            StreamWriter sw = new StreamWriter(fs);
            for (int i = 0; i < files.Count; i++) {
                string file = files[i];
                //string ext = Path.GetExtension(file);
                if (file.EndsWith(".meta") || file.Contains(".DS_Store")) continue;
                
                string md5 = md5file(file);
                string value = file.Replace(outputPath+"/", string.Empty);
                sw.WriteLine(value + "|" + md5);
            }
            sw.Close(); fs.Close();
        }

        private List<string> Recursive(string path)
        {
            List<string> files = new List<string>();
            string[] names = Directory.GetFiles(path);
            string[] dirs = Directory.GetDirectories(path);
            foreach (string filename in names)
            {
                string ext = Path.GetExtension(filename);
                if (ext.Equals(".meta")) continue;
                files.Add(filename.Replace('\\', '/'));
            }
            return files;
        }

        private string md5file(string file)
        {
            try
            {
                FileStream fs = new FileStream(file, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(fs);
                fs.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("md5file() fail, error:" + ex.Message);
            }
        }
    }
}

AssetBundleTree类是AssetBundleTool提供的类,我在此基础上添加冗余资源检查,如果发现在标签的最左侧显示警告图标,目前显示有点小bug,冗余内容已筛选正确,如果有需要的,下次我在进行分享

猜你喜欢

转载自blog.csdn.net/aihong_1314/article/details/86490624
今日推荐