热更新之Assetbundle——下载

Assetbundle的下载这一块,是耗时最久的,也是最复杂的。步骤为对比版本号,不同则对比信息配置文件,然后去差异下载更新。做之前听网友们说已经不用www了,说是besthttp插件,非常好用。然后去试了下,确实好用,但是后面下载写入的时候会偶尔报异常,下载0kb的文件,而且看log根本看不出个所以然,没办法又换回了www。besthttp有个比较好的地方是可以设置下载到一定的量就去触发下载回调,大大的降低了内存,但是游戏没有大资源,也就没什么必要。

首先,对比版本号,即读取本地的版本号文件,与服务端的版本号文件,两个版本号进行对比。

    int localVersion = 0;
    int webVersion;
    public void checkVersion()
    {
        if (File.Exists(Application.streamingAssetsPath + "/assetVersion.txt"))
        {
            StreamReader sr = new StreamReader(Application.streamingAssetsPath + "/assetVersion.txt");
            string value = sr.ReadToEnd();
            Debug.Log(value);
            localVersion = int.Parse(value);
        }
        Debug.Log(localVersion);
        StartCoroutine(getWebVersion());
    }

    IEnumerator getWebVersion()
    {
        WWW www = new WWW("http://localhost/assetVersion.txt");
        yield return www;
        if (www.error != null)
        {
            Debug.Log(www.error);
            yield break;
        }
        if (www.isDone)
        {
            Debug.Log(www.text);
            webVersion = int.Parse(www.text);
        }
    }

对比结果,如果相等,则直接接入游戏,如果不同,则开始对比创建assetbundle时生成的配置文件,即第一篇那里记录了所有bundle名字、尺寸、md5、后缀的文件。因为是以列表转json的方式写入的,所以这里读取的时候反过来,json转列表即可。注意第一篇的注释,写入文件的时候不要选择utf-8的方式,否则这里转换会有异常(忘记什么异常类型了..)。首先读取本地的配置文件得到一个列表,然后读取服务端的配置文件得到一个列表,对比两个列表,检索出所有md5值发生变化以及新增的bundle。因为列表存的是一个对象,不易对比,所以将本地列表加工成一个字典,key为bundlename。

    List<assetBundleMsgInfo> localBundleMsgInfoList;//本地所有bundle信息
    Dictionary<String, assetBundleMsgInfo> localBundleMsgDic;//key bundleName
    List<assetBundleMsgInfo> webBundleMsgInfoList;

    List<assetBundleMsgInfo> needDownLoadBundleList;//对比后需要下载的资源
    long needDownLoadSize;//所有资源大小 

    /// <summary>
    /// 解析json文件,对比每个bundle的hash ,本地
    /// </summary>
    void GetLocalBundlesMsgFile()
    {
        localBundleMsgInfoList = new List<assetBundleMsgInfo>();
        if (!File.Exists(Path.Combine(Application.streamingAssetsPath, "bundleMsg"))) return;
        StreamReader sr = new StreamReader(Path.Combine(Application.streamingAssetsPath, "bundleMsg"));
        string json = sr.ReadToEnd();
        localBundleMsgInfoList = JsonMapper.ToObject<List<assetBundleMsgInfo>>(json);
        sr.Close();
    }

    //服务器
    IEnumerator GetWebBundleMsgFile()
    {
        webBundleMsgInfoList = new List<assetBundleMsgInfo>();
        WWW www = new WWW("http://localhost/bundleMsg");
        yield return www;

        if (www.error != null)
        {
            Debug.Log(www.error);
            yield break;
        }
        if (www.isDone)
        {
            Debug.Log(www.text);
            webBundleMsgInfoList = JsonMapper.ToObject<List<assetBundleMsgInfo>>(www.text);
        }
    }


    //对比
    void CompareFileAndDialogLoad()
    {
        localBundleMsgDic = new Dictionary<string, assetBundleMsgInfo>();

        needDownLoadBundleList = new List<assetBundleMsgInfo>();

        needDownLoadSize = 0;

        for (int i = 0; i < localBundleMsgInfoList.Count; i++)
        {
            assetBundleMsgInfo info = localBundleMsgInfoList[i];
            localBundleMsgDic.Add(info.bundleName, info);
        }

        for (int i = 0; i < webBundleMsgInfoList.Count; i++)
        {
            assetBundleMsgInfo info = webBundleMsgInfoList[i];

            if (localBundleMsgDic.ContainsKey(info.bundleName))
            {
                if (info.hash != localBundleMsgDic[info.bundleName].hash)
                {
                    needDownLoadBundleList.Add(info);
                    needDownLoadSize += info.size;
                }
            }
            else
            {
                needDownLoadBundleList.Add(info);
                needDownLoadSize += info.size;
            }

        }
    }

经过对比配置之后便可以获取到所有需要下载的bundle,以及资源总大小,然后弹窗提示更新,确认后开始下载,写入本地即可。写入这里用简单来说就几句代码,但是实际上会遇到各种各样的异常,这里就不一一举例了,遇到异常分析不出来问度娘即可,但是插件报的异常就有点令人无可奈何了,插件的好处就在于为你省去了其他繁琐的步骤,但是弊端就是如果有异常发生,查找问题会非常的麻烦,所以慎用。

for (int i = 0; i < needDownLoadBundleList.Count; i++)
{                                      
     StartCoroutine(DownLoadFile(needDownLoadBundleList[i].bundleName));
}
StartCoroutine(DownLoadFile("AssetbundleFile"));
StartCoroutine(DownLoadFile("AssetbundleFile.manifest"));
StartCoroutine(DownLoadFile("bundleMsg"));
StartCoroutine(DownLoadFile("assetVersion.txt"));

    IEnumerator DownLoadFile(string bundleName)
    {
        string url = string.Format("http://localhost/{0}", bundleName);
        WWW www = new WWW(url);
        yield return www;

        if (www.error != null)
        {
            Debug.Log(www.error);
            yield break;
        }

        if (www.isDone)
        {
            Debug.Log(url + "--- downComplete");
            byte[] bytes = www.bytes;
            CreateFile(bytes, bundleName);
        }
    }

    void CreateFile(byte[] bytes, string name)
    {
        Stream stream;
        string path = Path.Combine(Application.streamingAssetsPath, name);
        if (File.Exists(path)) File.Delete(path);
        FileInfo info = new FileInfo(path);
        stream = info.Create();
        stream.Write(bytes, 0, bytes.Length);
        stream.Close();
    }

注意这里路径根据自己实际的来传参。文件写入后文件流要及时关闭。

至此下载写入就完成了,但是这里有很大的漏洞,即如果下载过程中,因为某些不可控的原因,导致某个文件下载失败,但是最后的系列配置文件都下载成功,这样会导致本地版本以及配置都是正确的,但是实际文件不同,就没办法检测到差异然后进行更新,所以这里还需要二次校验,我一直在疑问更新之后,本地的bundlemsg配置文件是不是需要在本地自动生成,而不是去下载,还有这个二次校验需要怎么去做。希望有做过或有思路的朋友不吝赐教。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值