AssetBandle打包
using System.Linq;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System;
/// <summary>
/// 打包腳本 —— 放在 Editor 文件夾下(規範)
/// </summary>
public class BuildAssetBundle
{
static List<string> paths = new List<string>();
static List<string> files = new List<string>();
//根據路徑創建MD5值
public static string md5file(string file)
{
try
{
FileStream fs = new FileStream(file, FileMode.Open);
string size = fs.Length / 1024 + "";
Debug.Log("當前文件的大小: " + file + "===>" + (fs.Length / 1024) + "KB");
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 + "|" + size;
}
catch (Exception ex)
{
throw new Exception("md5file() fail, error:" + ex.Message);
}
}
[MenuItem("工具/打包AssetsBundle資源")] //菜單欄添加按鈕
static void BuildAllAssetsBundles()
{
string folder = Application.streamingAssetsPath; //定義文件夾名字
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder); //文件夾不存在,則創建
}
else
{
DirectoryInfo direction = new DirectoryInfo(folder);
FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
if (files[i] != null)
{
Debug.Log("刪除文件:" + files[i].FullName + "__over");
files[i].Delete();
files[i] = null;
}
}
}
BuildPipeline.BuildAssetBundles(folder, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows); //創建AssetBundle
Recursive(Application.streamingAssetsPath + "/");
ForeachItem();
}
/// <summary>
/// 遍歷目錄及其子目錄
/// </summary>
static void Recursive(string path)
{
//獲取多個類型格式的文件
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('\\', '/'));
}
foreach (string dir in dirs)
{
paths.Add(dir.Replace('\\', '/'));
Recursive(dir);
}
}
//寫入file.text配置文件
public static void ForeachItem()
{
string savePath = Application.streamingAssetsPath + "/file.txt";
if (!File.Exists(savePath))
{
File.Delete(savePath);
}
FileStream fs = new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
StreamWriter sr = new StreamWriter(fs, System.Text.Encoding.UTF8);
foreach (var item in files)
{
if (item.EndsWith(".mate"))
continue;
sr.WriteLine(item.Replace(Application.streamingAssetsPath + "/", string.Empty) + "|" + md5file(item) + ";");
}
sr.Close();
fs.Close();
AssetDatabase.Refresh();
}
}
更新AssetBandle包解壓到本地緩存目錄 目前還沒支持跨平臺
public class LoadImage : MonoBehaviour
{
public Slider sliderr;
void Awake()
{
sliderr = GameObject.Find("Canvas/Slider").GetComponent<Slider>();
}
void Start()
{
StartCoroutine(Copy());
}
IEnumerator Copy()
{
string dataPath = @"E:/HotUpdate/";
string resPath = Application.streamingAssetsPath + "/";
if (Directory.Exists(dataPath))
{
Directory.Delete(dataPath, true);
}
Directory.CreateDirectory(dataPath);
string infile = resPath + "file.txt";
string outfile = dataPath + "file.txt";
if (File.Exists(outfile))
{
File.Delete(outfile);
}
string message = "正在解壓文件";
Debug.Log(message);
Debug.Log(infile);
Debug.Log(outfile);
if (Application.platform == RuntimePlatform.Android)
{
WWW www = new WWW(infile);
yield return www;
if (www.isDone)
{
File.WriteAllBytes(outfile, www.bytes);
}
yield return 0;
}
else File.Copy(infile, outfile, true);
if (sliderr != null)
{
sliderr.value = 0;
Debug.Log("正在解壓資源。。。");
}
string[] files = File.ReadAllLines(outfile);
foreach (var file in files)
{
if (sliderr != null)
{
sliderr.value += 1.0f / files.Length ;
}
string[] fs = file.Split('|');
infile = resPath + fs[0];
outfile = dataPath + fs[0];
Debug.Log("正在解壓文件" + infile);
//返回指定路徑字符串組件的目錄名字
string dir = Path.GetDirectoryName(outfile);
Debug.Log("outfile " + outfile);
Debug.Log("dir " + dir);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (Application.platform == RuntimePlatform.Android)
{
WWW www = new WWW(infile);
yield return www;
if (www.isDone)
{
File.WriteAllBytes(outfile, www.bytes);
}
yield return 0;
}
else
{
if (File.Exists(outfile))
{
File.Delete(outfile);
}
File.Copy(infile, outfile, true);
}
yield return new WaitForEndOfFrame();
}
yield return new WaitForSeconds(0.1f);
Debug.Log("釋放完成");
}
}
上面的WWW會有報錯 於是我又寫了一遍
public class LoadImage : MonoBehaviour
{
public Slider sliderr;
void Awake()
{
sliderr = GameObject.Find("Canvas/Slider").GetComponent<Slider>();
}
void Start()
{
StartCoroutine(Copy());
}
IEnumerator Copy()
{
string dataPath = @"E:/HotUpdate/";
string resPath = Application.streamingAssetsPath + "/";
if (Directory.Exists(dataPath))
{
Directory.Delete(dataPath, true);
}
Directory.CreateDirectory(dataPath);
string infile = resPath + "file.txt";
string outfile = dataPath + "file.txt";
if (File.Exists(outfile))
{
File.Delete(outfile);
}
string message = "正在解壓文件";
Debug.Log(message);
Debug.Log(infile);
Debug.Log(outfile);
if (Application.platform == RuntimePlatform.Android)
{
// WWW www = new WWW(infile);
UnityWebRequest www = new UnityWebRequest(infile);
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.isDone)
{
File.WriteAllBytes(outfile, www.downloadHandler.data);
}
yield return 0;
}
else File.Copy(infile, outfile, true);
if (sliderr != null)
{
// sliderr.value=1f/files.Count+100;
sliderr.value = 0;
Debug.Log("正在解壓資源。。。");
}
string[] files = File.ReadAllLines(outfile);
foreach (var file in files)
{
if (sliderr != null)
{
sliderr.value += 1.0f / files.Length ;
}
string[] fs = file.Split('|');
infile = resPath + fs[0];
outfile = dataPath + fs[0];
Debug.Log("正在解壓文件" + infile);
//返回指定路徑字符串組件的目錄名字
string dir = Path.GetDirectoryName(outfile);
Debug.Log("outfile " + outfile);
Debug.Log("dir " + dir);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (Application.platform == RuntimePlatform.Android)
{
// WWW www = new WWW(infile);
// yield return www;
// if (www.isDone)
// {
// File.WriteAllBytes(outfile, www.bytes);
// }
UnityWebRequest www = new UnityWebRequest(infile);
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.isDone)
{
File.WriteAllBytes(outfile, www.downloadHandler.data);
}
yield return 0;
}
else
{
if (File.Exists(outfile))
{
File.Delete(outfile);
}
File.Copy(infile, outfile, true);
}
yield return new WaitForEndOfFrame();
}
yield return new WaitForSeconds(0.1f);
Debug.Log("釋放完成");
}
}
/// <summary> 複製文件夾到指定目錄</summary>
public static void CopyDirectory(string sourceDirectoryPath, string targetDirectoryPath, string searchPattern = "*.*", bool isDeleteExist = false)
{
string[] files = Directory.GetFiles(sourceDirectoryPath, searchPattern, SearchOption.AllDirectories);
string file, newPath, newDir;
for (int i = 0; i < files.Length; i++)
{
file = files[i];
file = file.Replace("\\", "/");
if (!file.EndsWith(".meta") && !file.EndsWith(".DS_Store"))
{
newPath = file.Replace(sourceDirectoryPath, targetDirectoryPath);
newDir = System.IO.Path.GetDirectoryName(newPath);
if (!Directory.Exists(newDir))
Directory.CreateDirectory(newDir);
if (File.Exists(newPath))
if (isDeleteExist)
File.Delete(newPath);
else
continue;
if (Application.platform == RuntimePlatform.Android)
AndroidCopyFile(file, newPath);
else
File.Copy(file, newPath);
}
}
}
private static IEnumerator AndroidCopyFile(string sourceFilePath, string targetFilePath)
{
WWW www = new WWW("file://" + sourceFilePath);
yield return www;
File.WriteAllBytes(targetFilePath, UnicodeEncoding.UTF8.GetBytes(www.text));
}
最後補充
/// <summary>
/// 拷貝文件夾 (不適用 android)
/// </summary>
/// <param name="sourceFolder"></param>
/// <param name="targetFolder"></param>
/// <param name="isForce">是否刪除源文件</param>
public static void CopyFolder(string sourceFolder, string targetFolder, Slider slider_Update, bool isForce = true)
{
try
{
if (sourceFolder.EndsWith("/"))
{
sourceFolder += "/";
}
if (targetFolder.EndsWith("/"))
{
targetFolder += "/";
}
string[] fileNames = Directory.GetFiles(sourceFolder, "*", SearchOption.AllDirectories);
foreach (string fileName in fileNames)
{
if (fileName.EndsWith(".DS_Store") || fileName.EndsWith(".meta"))
{
continue;
}
Debug.Log(fileName);
string destFileName = Sy.Utility.Path.GetCombinePath(targetFolder,
fileName.Substring(sourceFolder.Length));
FileInfo destFileInfo = new FileInfo(destFileName);
if (!destFileInfo.Directory.Exists)
{
destFileInfo.Directory.Create();
}
if (isForce && File.Exists(destFileName))
{
File.Delete(destFileName);
}
File.Copy(fileName, destFileName);
slider_Update.value += 1.0f / fileNames.Length;
}
}
catch (Exception e)
{
// throw new IOException(Utility.Text.Format("copy folder fail m source :{0}, target:{1}"
// , sourceFolder, targetFolder), e);
}
}
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2019 Jiang Yin. All rights reserved.
// Homepage: http://gameframework.cn/
// Feedback: mailto:[email protected]
//------------------------------------------------------------
using System;
using System.IO;
namespace Sy
{
/// <summary>
///
/// </summary>
public static partial class Utility
{
/// <summary>
/// 路徑相關的實用函數。
/// </summary>
public static class Path
{
/// <summary>
/// 獲取規範的路徑。
/// </summary>
/// <param name="path">要規範的路徑。</param>
/// <returns>規範的路徑。</returns>
public static string GetRegularPath(string path)
{
if (path == null)
{
return null;
}
return path.Replace('\\', '/');
}
/// <summary>
/// 獲取連接後的路徑。
/// </summary>
/// <param name="path">路徑片段。</param>
/// <returns>連接後的路徑。</returns>
public static string GetCombinePath(params string[] path)
{
if (path == null || path.Length < 1)
{
return null;
}
string combinePath = path[0];
for (int i = 1; i < path.Length; i++)
{
combinePath = System.IO.Path.Combine(combinePath, path[i]);
}
return GetRegularPath(combinePath);
}
/// <summary>
/// 獲取遠程格式的路徑(帶有file:// 或 http:// 前綴)。
/// </summary>
/// <param name="path">原始路徑。</param>
/// <returns>遠程格式路徑。</returns>
public static string GetRemotePath(params string[] path)
{
string combinePath = GetCombinePath(path);
if (combinePath == null)
{
return null;
}
return combinePath.Contains("://") ? combinePath : ("file:///" + combinePath).Replace("file:////", "file:///");
}
/// <summary>
/// 獲取帶有後綴的資源名。
/// </summary>
/// <param name="resourceName">原始資源名。</param>
/// <returns>帶有後綴的資源名。</returns>
// public static string GetResourceNameWithSuffix(string resourceName)
// {
// if (string.IsNullOrEmpty(resourceName))
// {
// throw new Exception("Resource name is invalid.");
// }
// return Text.Format("{0}.dat", resourceName);
// }
/// <summary>
/// 獲取帶有 CRC32 和後綴的資源名。
/// </summary>
/// <param name="resourceName">原始資源名。</param>
/// <param name="hashCode">CRC32 哈希值。</param>
/// <returns>帶有 CRC32 和後綴的資源名。</returns>
// public static string GetResourceNameWithCrc32AndSuffix(string resourceName, int hashCode)
// {
// if (string.IsNullOrEmpty(resourceName))
// {
// throw new Exception("Resource name is invalid.");
// }
// return Text.Format("{0}.{1:x8}.dat", resourceName, hashCode);
// }
}
}
}