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

        }

    }
}

猜你喜欢

转载自blog.csdn.net/qq_36848370/article/details/91386389
今日推荐