WebGL AssetBundle 加載 緩存

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(在上一次調用此方法時寫入緩存的)進行對比,相同則不更新,不同則更新。

理論上如此,有待實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章