Unity中AB打包流程

一、前言

看以前写的很繁琐,现在简单点直接上代码,以下代码全部放置在Unity的Assets/Editor文件夹下,Editor没有要自己建

二、使用步骤

1.主要代码

打包代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;

public class ResBundleTools
{
    /// <summary>
    /// 清理不该命名的命名
    /// </summary>
    public static void RemoveResBundleName()
    {
        //此list保存所有资源文件存放路径
        List<string> filterList = new List<string>();
        filterList.Add(要打包的资源路径);
        //比如 "Assets/GameResources/BundleRes/" 举例都是按照我自己项目举例,后面不再复述
        //自己项目自行按照自己项目修改

        foreach (string assetGuid in AssetDatabase.FindAssets("", new string[] { "Assets" }))
        {
            string path = AssetDatabase.GUIDToAssetPath(assetGuid);
            AssetImporter import = AssetImporter.GetAtPath(path);
            string bundleName = import.assetBundleName;

            if (string.IsNullOrEmpty(bundleName))
            {
                continue;
            }
            //isClean代表是否改命名
            bool isClean = true;
            foreach (string filter in filterList)
            {
                if (path.StartsWith(filter))
                {
                    isClean = true;
                    break;
                }
            }
            //为false清理
            if (!isClean)
            {
                import.assetBundleName = null;
            }
        }
    }

    /// <summary>
    /// 给资源命名
    /// </summary>
    public static void GiveResBundleName()
    {
        string resPath = 这里放资源路径,也就是你要打包的资源在那个文件夹下面;
        //比如 "Assets/GameResources/BundleRes/"

        //生成资源名称(*.* 表示所有文件如 a.txt等)
        foreach (string path in Directory.GetFiles(resPath, "*.*", SearchOption.AllDirectories))
        {
            if (path.Contains(".meta")) continue;

            var importer = AssetImporter.GetAtPath(path);

            if (importer == null)
            {
                ToolsHelper.Log(string.Format("Not Found:{0}", path));
            }

            string tmpName = path.Substring(resPath.Length);
            string finalName = tmpName.Replace("\\", "/") + ab文件后缀;
            //比如 ".unity3d"

            importer.assetBundleName = finalName;

            if (finalName.IndexOf(" ") != -1)
            {
                ToolsHelper.Error(finalName);
            }
        }
    }

    /// <summary>
    /// 删除后再打包所有
    /// </summary>
    public static void RemoveThenBuildAllResAB()
    {
        string abPath = 这里放资源打包后的路径;
        //比如 Application.streamingAssetsPath 这里指向的是Assets下面的StreamingAssets文件夹没有自己建

        var abAll = Directory.GetFiles(abPath, "*.*", SearchOption.AllDirectories);
        for (int i=0;i<abAll.Length;i++)
        {
            File.Delete(abAll[i]);           
        }

        if (ToolsHelper.IsPlay()) return;
        ToolsHelper.ClearConsole();

        EditorCoroutineRunner.Run(IsBuildAllBuildRes());
    }

    /// <summary>
    /// 打包所有
    /// </summary>
    public static void BuildAllResAB()
    {
        if (ToolsHelper.IsPlay()) return;
        ToolsHelper.ClearConsole();

        EditorCoroutineRunner.Run(IsBuildAllBuildRes());
    }

    //完成ab资源打包
    private static IEnumerator IsBuildAllBuildRes()
    {
        //开始计时
        Stopwatch watch = new Stopwatch();
        watch.Start();
        yield return new WaitForSeconds(0.1f);

        //生成唯一时间
        DateTime hashTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(2023, 1, 1));
        int ver = (int)(DateTime.Now - hashTime).TotalMinutes;

        //开始资源命名(先命名,再移除不应当命名的)      
        GiveResBundleName();
        RemoveResBundleName();

        yield return null;

        string finalOutPath = GetOutPath();

        yield return new WaitForSeconds(0.3f);

        BuildPipeline.BuildAssetBundles(finalOutPath, BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);

        yield return new WaitForSeconds(0.3f);

        //构建相关资源目录
        ProduceAboutABFile(ver);

        yield return new WaitForSeconds(0.3f);

        watch.Stop();

        ToolsHelper.Log(string.Format("本次AssetBundle资源导出共用时: {0}{1}", (watch.ElapsedMilliseconds / 1000f), "秒"));

        AssetDatabase.Refresh();
        yield break;
    }

    /// <summary>
    /// 生成资源ab文件列表
    /// </summary>
    public static void ProduceAboutABFile(int ver)
    {
        string abPath = 这里放导出ab包后放在哪里的路径;
        //比如 Application.streamingAssetsPath

        string abFilePath = abPath + "/" + 后缀;
        //比如 ".unity3d"

        if (File.Exists(abFilePath))
            File.Delete(abFilePath);

        var abFileList = new List<string>(Directory.GetFiles(abPath, ("*" + 后缀), SearchOption.AllDirectories));
        //比如 ".unity3d"

        FileStream fs = new FileStream(abFilePath, FileMode.CreateNew);
        StreamWriter sw = new StreamWriter(fs);

        sw.WriteLine(ver + "|" + DateTime.Now.ToString("u"));

        for (int i = 0; i < abFileList.Count; i++)
        {
            long size = 0;
            string md5 = ToolsHelper.ComputeMD5(abFileList[i], out size);
            string relativePath = abFileList[i].Replace(abPath, string.Empty).Replace("\\", "/");
            sw.WriteLine(relativePath + "|" + md5 + "|" + size);
        }

        sw.Close();
        fs.Close();

        ToolsHelper.Log("AB文件列表生成完成");
    }

    /// <summary>
    /// 获取导出ab资源路径
    /// </summary>
    /// <returns></returns>
    public static string GetOutPath()
    {
        string outStr = 这里放导出ab包后放在哪里的路径;
        //比如 Application.streamingAssetsPath

        if (!Directory.Exists(outStr))
        {
            ToolsHelper.ShowDialog("资源打包导出路径未创建,已自动创建");
            ToolsHelper.CreateDir(outStr);
        }

        return outStr;
    }
}

2.其他代码

调用代码和工具代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;

public class EditorCoroutineRunner
{
    private class EditorCoroutine : IEnumerator
    {
        public Stack<IEnumerator> allList;


        public EditorCoroutine(IEnumerator ie)
        {
            allList = new Stack<IEnumerator>();
            allList.Push(ie);
        }

        public bool MoveNext()
        {
            IEnumerator ie = allList.Peek();

            if (ie.MoveNext())
            {
                if (ie.Current != null && ie is IEnumerator)
                {
                    allList.Push(ie);
                }
                return true;
            }
            else
            {
                if (allList.Count > 1)
                {
                    allList.Pop();
                    return true;
                }
            }

            return false;
        }
        public void Reset()
        {

        }
        public object Current
        {
            get { return this.allList.Peek().Current; }
        }
    }

    private static List<EditorCoroutine> corList;
    private static List<IEnumerator> tmpList;

    public static void Run(IEnumerator ie)
    {
        if (corList == null)
        {
            corList = new List<EditorCoroutine>();
        }
        if (tmpList == null)
        {
            tmpList = new List<IEnumerator>();
        }

        if (corList.Count == 0)
        {
            EditorApplication.update += Update;
        }

        tmpList.Add(ie);
    }

    public static void Update()
    {
        corList.RemoveAll(
            cor => { return cor.MoveNext() == false; }
        );

        if (tmpList.Count > 0)
        {
            for (int i = 0; i < tmpList.Count; i++)
            {
                corList.Add(new EditorCoroutine(tmpList[i]));
            }
        }

        if (corList.Count == 0)
        {
            EditorApplication.update -= Update;
        }
    }

}


public class ToolsMenu
{
    [MenuItem("工具/资源打包/打包所有生成AB")]
    private static void PackAllToAB()
    {
        ResBundleTools.BuildAllResAB();
    }

    [MenuItem("工具/资源打包/删除后再打包所有生成AB")]
    private static void RemoveAllThenPack()
    {
        ResBundleTools.RemoveThenBuildAllResAB();
    }
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;

public class ToolsHelper
{
    /// <summary>
    /// 判断是否已有在运行的
    /// </summary>
    /// <returns></returns>
    public static bool IsPlay()
    {
        if (EditorApplication.isPlaying)
        {
            Debug.LogError("已在运行");
            EditorUtility.DisplayDialog("提示", "已有任务在执行中..请稍候", "确定");
            return true;
        }
        return false;
    }

    /// <summary>
    /// 清理打印
    /// </summary>
    public static void ClearConsole()
    {
        Assembly ass = Assembly.GetAssembly(typeof(SceneView));
        Type _t = ass.GetType("UnityEditor.LogEntries");
        MethodInfo method = _t.GetMethod("Clear");
        method.Invoke(new object(), null);
    }

    /// <summary>
    /// 提示
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="title"></param>
    /// <param name="button"></param>
    /// <returns></returns>
    public static bool ShowDialog(string msg, string title = "提示", string button = "确定")
    {
        return EditorUtility.DisplayDialog(title, msg, button);
    }

    /// <summary>
    /// 创建文件夹(没有才创建)
    /// </summary>
    public static void CreateDir(string path)
    {
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
    }

    /// <summary>
    /// 计算文件的MD5值
    /// </summary>
    /// <param name="path"></param>
    /// <param name="size"></param>
    /// <returns></returns>
    public static string ComputeMD5(string path, out long size)
    {
        FileStream fs = new FileStream(path, FileMode.Open);
        size = fs.Length;
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] hash = md5.ComputeHash(fs);

        fs.Close();

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            //16进制
            sb.Append(hash[i].ToString("x2"));
        }

        return sb.ToString();
    }

    /// <summary>
    /// 根据长度计算大小(直接算M和K)
    /// </summary>
    /// <param name="len"></param>
    /// <returns></returns>
    public static string ComputeSize(long len)
    {
        if (len < 1024)
        {
            return 1 + "K";
        }
        if (len < 1048576)
        {
            return (len / 1024f) + "K";
        }
        else
        {
            return (len / 1048576f) + "M";
        }
    }

    public static void Log(string str)
    {
        Debug.Log(str);
    }

    public static void Error(string str)
    {
        Debug.LogError(str);
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="path">保存路径</param>
    /// <param name="content">文件内容</param>
    /// <param name="iscover">存在是否进行覆盖,默认true</param>
    public static void SaveFile(string path, string content, bool iscover = true)
    {
        FileInfo info = new FileInfo(path);
        //不覆盖
        if (!iscover && info.Exists) 
        {
            Log($"文件已存在,不进行覆盖操作! {path}");
            return;
        }
        CreateDir(info.DirectoryName);
        FileStream fs = new FileStream(path, FileMode.Create);
        StreamWriter sWriter = new StreamWriter(fs, Encoding.GetEncoding("UTF-8"));
        sWriter.WriteLine(content);
        sWriter.Flush();
        sWriter.Close();
        fs.Close();
        Log($"成功生成文件 {path}");
    }
}



总结

差不多了就这些,都弄完了在Unity编辑器最上面会出现工具选项,里面选打包就行,有问题留言。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值