一、前言
看以前写的很繁琐,现在简单点直接上代码,以下代码全部放置在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编辑器最上面会出现工具选项,里面选打包就行,有问题留言。