Unity熱更新一 (之 AssetBandle打包複製路徑到緩存目錄 帶進度條Slider)

 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);
            // }

        }

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章