U3D的AssetBundle真的是博(坑)大精(坑)深啊
安卓的话要先打包到StreamingAssetPath中,安装后第一次运行,自动把Streaming 中的解压到PersistentDataPath中,因为persistent目录是在运行过一次才创建的。
这样,之后再更新资源就直接下载到persistent目录下了
但是,WebGL项目呢
这个就不存在什么streaming或者persistent了,因为不能加载本地路径
所以就只有缓存,加载包时就要用
WWW.LoadFromDownloadOrCache(url, version)
这样会把资源下载到缓存目录中,每次加载时会判断版本,相同则直接从本地磁盘加载,不然才从网络下载,更新本地磁盘中的缓存。
这里坑就来了,就是这个版本号。第一次加载还好,随便设置个数,因为本地没有么,直接下载了。以后呢,怎么判断本地的版本和服务器的版本呢?
之所以有这个问题,是因为这个版本号是加载时写在程序里的,比如说第一次下载后,会把各包加载时的这个版本号也记录在本地缓存里,下次再加载时,程序里设置的版本号会与本地缓存中之前记录的版本号对比,如果不同,则说明有更新,下载包覆盖本地缓存,再加载,如果一样则没有更新,不下载,直接加载本地缓存。
看了很多例子,都是简单的写个0或者1,哪怕服务器端资源更新了,如果这个版本号还是用的和上次一样的,就认为没有更新,也不会从网络下载。
那么得想办法动态的获取包的这个版本,那么
WWW.LoadFromDownloadOrCache(url, version)
这个重载方法就不合适了,因为这个version没找到办法获取……
文档里说的是这个version要自增,也就是新的version要大于老的才更新,不过看网上有人说只要版本号不同,就更新,无论是大于还是小于,这个没试过,不过也无所谓了。
看了一眼,这个加载方法的另一项重载是:
public static WWW LoadFromCacheOrDownload(string url, Hash128 hash, uint crc);
说明:以下只是目前的一个设想,没有实践
首先说最后一个参数crc,按文档里说的,这个值非0时则对比crc,目前不关心这个,就让它是0
最重要的就是第二个参数hash
文档解释:
hash Hash128 which is used as the version of the AssetBundle.
对比这个可以相当于version版本。
那好,想办法得到各assetbundle包的Hash128
从manifest文件下手,打包之后会有个总的manifest文件,和你的包的根目录名同名
比如打包在StreamingAssets下,则其目录下有一个StreamingAssets.manifest文件
using(WWW www=WWW.LoadFromDownloadOrCache("..../StreamingAssets/StreamingAssets"))
{
yield return www;
AssetBundle ab=www.assetBundle;
AssetBundleManifest abm=ab.loadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] bundleNames=abm.GetAllAssetBundles();
foreach(string item in bundleNames)
{
Hash128 hash = abm.GetAssetBundleHash(item);
}
}
如上,GetAllAssetBundles()可以得到所有包的包名
再用GetAssetBundleHash(包名)得到包对应的hash128
那么每次加载资源之前,先把包的Hash128获取到,再用
public static WWW LoadFromCacheOrDownload(string url, Hash128 hash, uint crc);
这样每次加载都会对比这个Hash128值,这个就相当于是版本了
我试了一下,在开发环境下,如果资源没有任何修改,反复打包,出来的这个Hash128是不变的,如果有修改,比如材质的颜色变化一下,prefab的scale变化一下之类的,再打出来的包,Hash128就变化了。
理论上说,这样LoadFromDownloadOrCache就可以判断出有没有更新了
所以,每次打开程序,首先加载总的manifest,把包和对应的Hash128存到一个地方,比如字典
Dictionary<string, Hash128> bundleHashDict = new Dictionary<string, Hash128>();
using(WWW www=WWW.LoadFromDownloadOrCache("..../StreamingAssets/StreamingAssets"))
{
yield return www;
AssetBundle ab=www.assetBundle;
AssetBundleManifest abm=ab.loadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] bundleNames=abm.GetAllAssetBundles();
foreach(string item in bundleNames)
{
Hash128 hash = abm.GetAssetBundleHash(item);
bundleHashDict.Add(item, hash);
}
}
要加载一个名叫“a.assetbundle"的包
string path = "...../a.assetbundle";
Hash128 hash=bundleHashDict["a.assetbundle"];
using(WWW www = WWW.LoadFromDownloadOrCache(path, hash, 0))
{
yield return www;
.........
}
如上,根据包名在字典里取得其之前获取并存入字典里的Hash128,作为LoadFromDownloadOrCache方法的第二个参数,理论上会与本地缓存最后一次更新下载时存储的包的Hash128(在上一次调用此方法时写入缓存的)进行对比,相同则不更新,不同则更新。
理论上如此,有待实践
原文地址:http://blog.51cto.com/shuxiayeshou/2136680