天天看點

Cocos Creator 資源加載流程剖析【四】——額外流程(MD5 PIPE)

當我們将遊戲建構釋出到web平台時,勾選Md5 Cache選項可以開啟MD5 Pipe,它的作用是給建構後的資源加上md5字尾,避免浏覽器的緩存導緻部分資源不是最新,因為使用了md5字尾後,當資源内容發生變化時,資源的名字就不一樣了,緩存就會失效。

Cocos Creator 資源加載流程剖析【四】——額外流程(MD5 PIPE)

比如6e056173-d285-473c-b206-40a7fff5386e.json,在開啟了MD5 Cache選項之後再建構會生成6e056173-d285-473c-b206-40a7fff5386e.a548e.json,在檔案字尾.json前加上了一個簡化的md5——a548e。

開啟 MD5 PIPE

勾選了Md5 Cache選項後進行建構,生成的web-mobile/src/settings.xxx.js檔案中會設定一個全局變量_CCSettings,該變量中有一個md5AssetsMap字段記錄所有資源檔案的簡化md5。

md5AssetsMap: {
        "08/08ddbd1c9.json": "ade93",
        "6e/6e056173-d285-473c-b206-40a7fff5386e.json": "a548e",
        "assets/6e/6e056173-d285-473c-b206-40a7fff5386e.png": "68270"
    }
           

在Creator生成的main.xxx.js中會擷取_CCSettings變量進行處理,一個關鍵的地方就是cc.AssetLibrary.init,将settings.md5AssetsMap傳入AssetLibrary。

cc.AssetLibrary.init({
    libraryPath: 'res/import',
    rawAssetsBase: 'res/raw-',
    rawAssets: settings.rawAssets,
    packedAssets: settings.packedAssets,
    md5AssetsMap: settings.md5AssetsMap
});
           

在cc.AssetLibrary.init中,根據md5AssetsMap變量決定是否建立MD5Pipe,将md5Pipe插入到cc.loader.assetLoader之後。

var md5AssetsMap = options.md5AssetsMap;
    if (md5AssetsMap) {
        var md5Pipe = new MD5Pipe(md5AssetsMap, _libraryBase, _rawAssetsBase);
        cc.loader.insertPipeAfter(cc.loader.assetLoader, md5Pipe);
        cc.loader.md5Pipe = md5Pipe;
    }
           

在一些核心子產品中,我們可以看到直接使用url時,都會檢測是否存在cc.loader.md5Pipe,有則調用其transformURL對url進行處理,比如CCVideoPlayer.js,這些處理屬于不走Pipeline的路徑處理,屬于這些元件的内部邏輯。

_updateVideoSource: function () {
        var sgNode = this._sgNode;
        let url = '';
        if (this.resourceType === ResourceType.REMOTE) {
            url = this.remoteURL;
        }
        else if (this._clip) {
            url = this._clip.nativeUrl || '';
        }
        if (url && cc.loader.md5Pipe) {
            url = cc.loader.md5Pipe.transformURL(url);
        }
        sgNode.setURL(url);
    },
           

MD5 PIPE的實作

Md5 Pipe的實作非常簡單(位于load-pipeline下的md5-pipe.js),它隻對res/import或res/raw-開頭的url進行處理,根據md5AssetsMap對應的精簡md5值,重新組裝url。

MD5Pipe.prototype.transformURL = function (url, hashPatchInFolder) {
    var index = url.indexOf('?');
    var key = url;
    if (index !== -1) {
        key = url.substr(0, index);
    }
    // 如果是以libraryBase開頭'res/import',去掉這個字首
    if (key.startsWith(this.libraryBase)) {
        key = key.slice(this.libraryBase.length);
    // 如果是以rawAssetsBase開頭'res/raw-',也去掉這個字首
    } else if (key.startsWith(this.rawAssetsBase)) {
        key = key.slice(this.rawAssetsBase.length);
    } else {
    // 其他情況不處理,比如是一個完整的http連結
        return url;
    }
    
    // 取出該資源對應的精簡md5
    let hashValue = this.md5AssetsMap[key];
    if (hashValue) {
        // 如果hashPatchInFolder為true則将這個md5組裝到目錄下
        // JSB下的Spine、Label都有使用hashPatchInFolder
        if (hashPatchInFolder) {
            var dirname = cc.path.dirname(url);
            var basename = cc.path.basename(url);
            url = `${dirname}.${hashValue}/${basename}`;
        } else {
        // 正常情況是将精簡md5插入到檔案擴充名之前
            var matched = false;
            url = url.replace(ExtnameRegex, (function(match, p1) {
                matched = true;
                return "." + hashValue + p1;
            }));
            if (!matched) {
                url = url + "." + hashValue
            }
        }
    }
    return url;
};
           

繼續閱讀