Unity3D 更新文件下载器

Posted MrBlue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D 更新文件下载器相关的知识,希望对你有一定的参考价值。

使用说明:

 

1)远端更新服务器目录

Package

  |----list.txt

  |----a.bundle

  |----b.bundle

 

2)list.txt是更新列表文件

格式是

a.bundle|res/a.bundle

b.bundle|res/b.bundle

(a.bundle是要拼的url,res/a.bundle是要被写在cache的路径)

 

3)使用代码

var downloader = gameObject.GetComponent<PatchFileDownloader>();
        if (null == downloader)
        {
            downloader = gameObject.AddComponent<PatchFileDownloader>();
        }
        downloader.OnDownLoading = (n, c, file, url) =>
        {
            Debug.Log(url);
        };
        downloader.OnDownLoadOver =(ret)=>{
            Debug.Log("OnDownLoadOver  "+ret.ToString());
        };
        downloader.Download("http://192.168.1.103:3080/Package/", "list.txt");

 

//更新文件下载器

using System;
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;

//更新文件下载器
public class PatchFileDownloader : MonoBehaviour 
{

    //每个更新文件的描述信息
    protected class PatchFileInfo
    {
        // str 的格式是 url.txt|dir/a.txt        url.txt是要拼的url,dir/a.txt是要被写在cache的路径
        public PatchFileInfo(string str)
        {
            Parse(str);

        }

        //解析
        protected virtual void Parse(string str)
        {
            var val = str.Split(|);
            if (1 == val.Length)
            {
                PartialUrl = val[0];
                RelativePath = val[0];
            }
            else if (2 == val.Length)
            {
                PartialUrl = val[0];
                RelativePath = val[1];
            }
            else
            {
                Debug.Log("PatchFileInfo parse error");
            }
        }

        //要被拼接的URL
        public string PartialUrl { get; private set; }

        //文件相对目录
        public string RelativePath { get; private set; }
    }

    public delegate void DelegateLoading(int idx, int total, string bundleName, string path);
    public delegate void DelegateLoadOver(bool success);

    //正在下载中回掉
    public DelegateLoading OnDownLoading;

    //下载完成回掉
    public DelegateLoadOver OnDownLoadOver;

    //总共要下载的bundle个数
    private int mTotalBundleCount = 0;

    //当前已下载的bundle个数
    private int mBundleCount = 0;

    //开始下载
    public void Download(string url,string dir)
    {
        mBundleCount = 0;
        mTotalBundleCount = 0;
        StartCoroutine(CoDownLoad(url, dir));
    }

    //下载Coroutine
    private IEnumerator CoDownLoad(string url, string dir)
    {
        //先拼接URL
        string fullUrl = Path.Combine(url, dir);

        //获得要更新的文件列表
        List<string> list = new List<string>();

        //先下载列表文件
        using (WWW www = new WWW(fullUrl))
        {
            yield return www;

            if (www.error != null)
            {
                //下载失败
                if (null != OnDownLoadOver)
                {
                    try
                    {
                        OnDownLoadOver(false);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e.Message);
                    }
                }

                Debugger.LogError(string.Format("Read {0} failed: {1}", fullUrl, www.error));
                yield break;
            }

            //读取字节
            ByteReader reader = new ByteReader(www.bytes);

            //读取每一行
            while (reader.canRead)
            {
                list.Add(reader.ReadLine());
            }

            if (null != www.assetBundle)
            {
                www.assetBundle.Unload(true);    
            }
            
            www.Dispose();
        }

        //收集所有需要下载的
        var fileList = new List<PatchFileInfo>();
        for (int i = 0; i < list.Count; i++)
        {
            var info = new PatchFileInfo(list[i]);

            if (!CheckNeedDownload(info))
            {
                continue;
            }
            
            fileList.Add(info);
        }

        mTotalBundleCount = fileList.Count;

        //开始下载所有文件
        for (int i = 0; i < fileList.Count; i++)
        {
            var info = fileList[i];

            var fileUrl = Path.Combine(url, info.PartialUrl);

            StartCoroutine(CoDownloadAndWriteFile(fileUrl, info.RelativePath));
        }

        //检查是否下载完毕
        StartCoroutine(CheckLoadFinish());
    }

    //检查是否该下载
    protected virtual bool CheckNeedDownload(PatchFileInfo info)
    {
        
        return true;
    }

    //下载并写入文件
    private IEnumerator CoDownloadAndWriteFile(string url,string filePath)
    {
        var fileName = Path.GetFileName(filePath);

        using (WWW www = new WWW(url))
        {
            yield return www;

            if (www.error != null)
            {
                Debugger.LogError(string.Format("Read {0} failed: {1}", url, www.error));
                yield break;
            }

            var writePath = CreateDirectoryRecursive(filePath) + "/" + fileName;

            FileStream fs1 = File.Open(writePath, FileMode.OpenOrCreate);
            fs1.Write(www.bytes, 0, www.bytesDownloaded);
            fs1.Close();

            //Debug.Log("download  " + writePath);
            if (null != www.assetBundle)
            {
                www.assetBundle.Unload(true);
            }
            www.Dispose();

            mBundleCount++;

            if (null != OnDownLoading)
            {
                try
                {
                    OnDownLoading(mBundleCount, mTotalBundleCount, writePath, url);
                }
                catch (Exception e)
                {
                    Debug.LogError(e.Message);    
                }
            }
        }
    }

    //递归创建文件夹
    public static string CreateDirectoryRecursive(string relativePath)
    {
        var list = relativePath.Split(/);
        var temp = Application.temporaryCachePath;
        for (int i=0;i<list.Length-1;i++)
        {
            var dir = list[i];
            if (string.IsNullOrEmpty(dir))
            {
                continue;
            }
            temp += "/" + dir;
            if (!Directory.Exists(temp))
            {
                Directory.CreateDirectory(temp);
            }
        }

        return temp;
    }

    //清空某个目录
    public static void CleanDirectory(string relativePath)
    {
        
        var fallPath = Path.Combine(Application.temporaryCachePath, relativePath);
        if (string.IsNullOrEmpty(relativePath))
        {
            Caching.CleanCache();
            return;
        }

        var dirs = Directory.GetDirectories(fallPath);
        var files = Directory.GetFiles(fallPath);

        foreach (var file in files)
        {
            File.Delete(file);
        }

        foreach (var dir in dirs)
        {
            Directory.Delete(dir, true);
        }

        Debug.Log("CleaDirectory " + fallPath);
    }

    //检查是否已经下载完毕
    IEnumerator CheckLoadFinish()
    {
        while (mBundleCount < mTotalBundleCount)
        {
            yield return null;
        }

        if (null != OnDownLoadOver)
        {
            try
            {
                OnDownLoadOver(true);
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
            }
        }
    }
}

 

以上是关于Unity3D 更新文件下载器的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——CSS选择器

从广播接收器更新片段中的列表视图

VSCode自定义代码片段6——CSS选择器

Unity3D热更新技术点——ToLua

如何在unity3d发布好的程序中导入外部文件?

Unity中Shader的三种基本类型