Unity3D: AssetBundle的缓存加载

unity中有一个  WWW.LoadFromCacheOrDownload(url, int)的方法,简单讲就是从服务器上加载,如果本地缓存对应的版本号有这个资源,则从本地加载。

没有或则传入的版本号不对则从服务器上加载。

那么 坑就来了。

unity说这个版本号是自动维护的,可是我们没有办法控制,那我们怎么能传入这个值呢。 找了一些方法,大体的思路如下,后面会写上代码。

在本地打包,新建一个xml文档,保存这个包的hash128值,到文档中,再把这个文档也打包,都上传到服务器上。

每次先从服务器上获取这个xml文档,然后把对应的hash128值作为验证来判断,hash128是另外一个重载方法的参数。

<?xml version="1.0" encoding="UTF-8"?>
<AssetBundleConfig>
  <Category Name="交通运输" HashCode="c4cde5fcf0d047ee3bdbe823128208cb" />
  <Category Name="动力设施" HashCode="a3b487a32e63a9d84fbaeb0061966d8c" />
  <Category Name="建筑及构筑物库" HashCode="a121fb8280b7f5a65083086d448bd16f" />
  <Category Name="施工机械" HashCode="33d29373021741f67ba6671c23ca3358" />
  <Category Name="材料及构件堆场" HashCode="73cbfe3ed7b7ba9608e1e8ad4590d80f" />
  <Category Name="管线绿化" HashCode="34e9474e2d9ac64424a0a369e4024776" />
</AssetBundleConfig>

下面这个是打包并且写入xml文档的代码

using UnityEngine;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using UnityEditor;

public class ExportAssetBundles : MonoBehaviour
{
    [MenuItem("AssetBundle/Build Asset Bundles")]
    static void BuildABs()
    {
        // Put the bundles in a folder called "ABs" within the Assets folder.
        BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
        CreateOrUpdateConfig();

    }

    /// <summary>
    /// 将存在的ab包获取HashCode放入xml文件
    /// </summary>
    [MenuItem("AssetBundle/CreateOrUpdateConfig")]
    public static void CreateOrUpdateConfig()
    {
        string filePath = Application.dataPath + "/versionConfig.xml";
        //如果文件不存在
        if (!File.Exists(filePath))
        {
            XmlDocument xmlDocument = new XmlDocument();
            XmlDeclaration xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", null);
            xmlDocument.AppendChild(xmlDeclaration);
            var root = xmlDocument.CreateElement("AssetBundleConfig");
            xmlDocument.AppendChild(root);
            SaveXmlConfig(filePath, xmlDocument, root);
        }
        else
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(filePath);
            var xmlRootNode = xmlDocument.SelectSingleNode("AssetBundleConfig");
            if (xmlRootNode != null && !xmlRootNode.HasChildNodes)
                return;
            xmlRootNode.RemoveAll();
            SaveXmlConfig(filePath, xmlDocument, xmlRootNode);
        }
        AssetDatabase.Refresh();
        Debug.Log("保存或修改成功");

        BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }

    private static void SaveXmlConfig(string filePath, XmlDocument xmlDocument, XmlNode xmlRootNode)
    {
        //循环
        AssetDatabase.RemoveUnusedAssetBundleNames();
        var assetBundles = AssetDatabase.GetAllAssetBundleNames();
        //var asset = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundles/AssetBundles");
        var asset = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/AssetBundles");
        //这个字符串是固定写法
        AssetBundleManifest assetBundleManifest = asset.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        asset.Unload(false);
        foreach (var item in assetBundles)
        {
            if (item == "versionconfig.unity3d")
                continue;
            var assetBundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/" + item);
            if (!assetBundle) continue;
            var xmlElement = xmlDocument.CreateElement("Category");
            xmlElement.SetAttribute("Name", item.Split('.')[0]);
            var hashCode = assetBundleManifest.GetAssetBundleHash(item);
            xmlElement.SetAttribute("HashCode", hashCode.ToString());
            xmlRootNode.AppendChild(xmlElement);
            assetBundle.Unload(true);
        }
        xmlDocument.Save(filePath);
    }
}

下面的则是读取了,下面的代码涉及到公司项目,所以不能直接运行,注意

    private Dictionary<string, Hash128> _elementHash128Dic;
    void Awake()
    {
        _elementHash128Dic = new Dictionary<string, Hash128>();
       
    }

    public IEnumerator Load()
    {
      
        //while (!Caching.ready)
        //    yield return null;
        //Caching.CleanCache();

        //先获取服务器版本
        using (var www = new WWW(url地址自己写))
        {
            yield return www;
            if (!string.IsNullOrEmpty(www.error))
            {
                Debug.Log(www.error);
                yield break;
            }
            var assetBundle = www.assetBundle;
            var request = assetBundle.LoadAssetAsync<TextAsset>("versionconfig");
            yield return request;
            if (request.isDone)
            {
                _elementHash128Dic.Clear();
                var textAsset = request.asset as TextAsset;
                var xmlDocument = new XmlDocument();
                if (textAsset != null) xmlDocument.LoadXml(textAsset.text);
                var elements = xmlDocument.GetElementsByTagName("Category");
                for (int i = 0; i < elements.Count; i++)
                {
                    _elementHash128Dic.Add(elements[i].Attributes["Name"].Value, Hash128.Parse(elements[i].Attributes["HashCode"].Value));
                }
            }
        }

        foreach (var category in Enum.GetNames(typeof(SiteElementCategory)))
        {
            Hash128 hash;
            if (_elementHash128Dic.TryGetValue(category, out hash))
            {
                yield return LoadBundle(category, hash);
            }

        }
    }

    private IEnumerator LoadBundle(string category, Hash128 assetBundleHash128)
    {
        //category这个参数主要是用来拼接URL下载地址的
        var www = WWW.LoadFromCacheOrDownload(url, assetBundleHash128);
        //var www = WWW.LoadFromCacheOrDownload(url, 1);
        yield return www;
        if (!string.IsNullOrEmpty(www.error))
        //....后面自己写吧,没啥差别了。
    }

嗯。基本上就这样。

就这样。有问题可以给我留言。

端午快到了,祝大家端午安康,没有BUG。

快吃饭了, 我觉得下载时可以试试UnityWebRequest好像会更好一点。

You May Also Like

About the Author: 大腿Plus

发表评论