cocos2d-js 在線更新代碼腳本 動態更新腳本程序 熱更新 繞過平台審核 不需重新上架


 

2014年8月15日補充
cocos2d-js 3.0 rc0 的AssetsManager有缺陷,有一些注意點:(可以閱讀源代碼發現)
1、舊manifest中有,但新manifest中沒有的文件(Assets),會被刪除;舊的沒有,新的有,會正常下載。
2、groupversion暫時沒什么意義,並無法達到這位博主所謂的增量更新: https://github.com/faint2death/cocos2d-js/blob/master/assetsmanager.md。暫時只在版本比較中用到,並沒有在計算增量值中用到。
3、下載過程中N個文件其中某個遇到錯誤,已下載的文件還是會妥妥的覆蓋了舊文件,這樣會造成更新了一半的尷尬情況。

 

2014年8月19日補充
cocos2d-js 3.0 rc2 的AssetsManager依然有沒有確保全部同步更新的bug。本來想徹底解決這個問題,但無奈時間有限,沒有徹底理解AssetsManager多個類的作用。徹底解決的事,還是留給觸控去解決吧。
經過小修改,已經可以確保同步更新資源。其實做的工作就是:等最終全部下載完成后再解壓文件,這樣的改動是最小的。
 
使用這個更新包: https://github.com/kenkozheng/cocos2d-js/tree/master/modified-AssetsManager
覆蓋本地2個目錄相應的文件:
【項目路徑】\frameworks\js-bindings\cocos2d-x\extensions\assets-manager(新建工程時復制出來的)
【庫路徑】E:\cocos2d-js-v3.0-rc2\frameworks\js-bindings\cocos2d-x\extensions\assets-manager
 

使用方法:

1、所有js必須使用zip打包,但不強求只打包為1個文件。但不同zip不要有重復的js。

2、非js可以用zip,也可以直接列出。

由於確保所有資源都下載完成后才解壓js,所以玩家即使N次更新失敗,還是會妥妥的停留在上一版。

 

建議:
1、自第一次發布后,歷次更新的代碼都打包在一個js.zip中,每次只更新這個js.zip。這樣好處是,保證所有代碼是同步的,即使沒更新到,玩家也就停留在上一版。例如第一次更新,有1.js,那么js.zip只有1.js;第二次更新2.js,那么js.zip就得包含1.js和2.js,這樣避免一些跳版本更新的玩家出問題。
2、 非代碼資源,避免修改,可以直接用新文件,但不要替換舊文件,這樣目的是避免多次版本更新造成新舊混亂。設想2次更新都是zip包,兩個zip包都有1.png,這時候有個跳版本更新的玩家,就會下載2個zip包,但先后順序是不可控的。
3、每次更新manifest文件必須保留以前的assets配置,不能刪除。否則,如果刪了以前的assets配置,客戶端會跟隨着刪除相應的文件。
 

 

 

一、cocos2d-js 動態更新的基本思路

動態更新的好處不言而喻,不需要重新上架審核,能節省很多時間,也能讓用戶盡快使用上最新的版本,減少下載的成本。

  • 官方BETA版本后提供了AssetsManager類,可以完成動態更新的步驟,說明:https://github.com/chukong/cocos-docs/blob/master/manual/framework/html5/v3/assets-manager/zh.md
  • cocos2d程序安裝后,以Android為例,程序存在於2個地方:apk安裝目錄(/data/dalvik-cache),apk數據目錄(/data/data/[包名])
  • AssetsManager根據projec.manifest文件的配置,把新文件下載到apk數據目錄,並默認把這個下載目錄設置為最優先搜索的地方。
  • project.json文件中指定的js文件,將在程序main.js啟動前就加載完。main.js不需要寫到這個list中。所以需要動態更新的js,不能列在這個json中
  • 除了main.js外,把其他js列到一個文件中:src/jsList.js。AssetsManager檢查完之后,先加載這個jsList.js,然后根據里邊的配置再加載全部js。

二、程序發布步驟

本文參考:https://github.com/faint2death/cocos2d-js/blob/master/assetsmanager.md,但配置的方式不一樣,本文更偏於使用官方的配置。按參考文章的寫法,更新多次之后,project.manifest文件會很大,這影響用戶更新的速度。

1、修改main.js,加載AssetsManager功能

cc.game.onStart = function(){ 
    cc.view.setDesignResolutionSize(800, 450, cc.ResolutionPolicy.SHOW_ALL); 
    cc.view.resizeWithBrowserSize(true); 
    
    var failCount = 0; 
    var maxFailCount = 1;   //最大錯誤重試次數

    /** 
     * 自動更新js和資源 
     */ 
    var AssetsManagerLoaderScene = cc.Scene.extend({ 
        _am:null, 
        _progress:null, 
        _percent:0, 
        run:function(){ 
            if (!cc.sys.isNative) { 
                this.loadGame(); 
                return; 
            }

            var layer = new cc.Layer(); 
            this.addChild(layer); 
            this._progress = new cc.LabelTTF.create("update 0%", "Arial", 12); 
            this._progress.x = cc.winSize.width / 2; 
            this._progress.y = cc.winSize.height / 2 + 50; 
            layer.addChild(this._progress);

            var storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "./");

            this._am = new jsb.AssetsManager("res/project.manifest", storagePath); 
            this._am.retain();

            if (!this._am.getLocalManifest().isLoaded()) 
            { 
                cc.log("Fail to update assets, step skipped."); 
                this.loadGame(); 
            } 
            else 
            { 
                var that = this; 
                var listener = new cc.EventListenerAssetsManager(this._am, function(event) { 
                    switch (event.getEventCode()){ 
                        case cc.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: 
                            cc.log("No local manifest file found, skip assets update."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.UPDATE_PROGRESSION: 
                            that._percent = event.getPercent(); 
                            cc.log(that._percent + "%"); 
                            var msg = event.getMessage(); 
                            if (msg) { 
                                cc.log(msg); 
                            } 
                            break; 
                        case cc.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: 
                        case cc.EventAssetsManager.ERROR_PARSE_MANIFEST: 
                            cc.log("Fail to download manifest file, update skipped."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.ALREADY_UP_TO_DATE: 
                            cc.log("ALREADY_UP_TO_DATE."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.UPDATE_FINISHED: 
                            cc.log("Update finished."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.UPDATE_FAILED: 
                            cc.log("Update failed. " + event.getMessage()); 
                            failCount++; 
                            if (failCount < maxFailCount) 
                            { 
                                that._am.downloadFailedAssets(); 
                            } 
                            else 
                            { 
                                cc.log("Reach maximum fail count, exit update process"); 
                                failCount = 0; 
                                that.loadGame(); 
                            } 
                            break; 
                        case cc.EventAssetsManager.ERROR_UPDATING: 
                            cc.log("Asset update error: " + event.getAssetId() + ", " + event.getMessage()); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.ERROR_DECOMPRESS: 
                            cc.log(event.getMessage()); 
                            that.loadGame(); 
                            break; 
                        default: 
                            break; 
                    } 
                });

                cc.eventManager.addListener(listener, 1); 
                this._am.update(); 
                cc.director.runScene(this); 
            }

            this.schedule(this.updateProgress, 0.5); 
        },

        loadGame:function(){ 
            //jsList是jsList.js的變量,記錄全部js。 
            cc.loader.loadJs(["src/jsList.js"], function(){ 
                cc.loader.loadJs(jsList, function(){ 
                    cc.director.runScene(new MainScene()); 
                }); 
            }); 
        },

        updateProgress:function(dt){ 
            this._progress.string = "update" + this._percent + "%"; 
        },

        onExit:function(){ 
            cc.log("AssetsManager::onExit");

            this._am.release(); 
            this._super(); 
        } 
    }); 
    
    var scene = new AssetsManagerLoaderScene(); 
    scene.run(); 
}; 
cc.game.run();

 

2、建立jsList.js。使用固定名字jsList,這個跟第1步的代碼相對應。

var jsList = [ 
    "src/resource.js", 
    "src/app.js" 
]

 

3、修改project.json。加入extensions模塊,刪除jsList的內容。

{ 
    "project_type": "javascript",

    "debugMode" : 1, 
    "showFPS" : true, 
    "frameRate" : 60, 
    "id" : "gameCanvas", 
    "renderMode" : 0, 
    "engineDir":"frameworks/cocos2d-html5",

    "modules" : ["cocos2d", "extensions"],  //貌似這個對jsb是無效的,只有html5才有效

    "jsList" : [ 
         
    ] 
}

 

 

4、項目res目錄增加一個project.manifest文件,AssetsManager.js里會用到。url填寫自己服務器的地址,packageUrl是准備動態更新的文件的存放目錄。

{ 
    "packageUrl" : "http://192.168.1.11:8000/res", 
    "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest", 
    "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest", 
    "version" : "1.0.1", 
    "engineVersion" : "3.0 rc0", 
    "assets" : {

    },

    "searchPaths" : [ 
    ] 
}

 

5、打包程序。此時即使沒有網絡,也已經可以運行基礎版本。

 

三、動態更新測試

1、服務器放置version.manifest和新的project.manifest。

AssetsManager會先檢查version.manifest,判斷是否有更新。如果有,再拉取project.manifest。可以說version.manifest就是縮小版的project.manifest,只有頭幾行,兩者一致。

version.manifest:

{ 
    "packageUrl" : "http://192.168.1.11:8000/res", 
    "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest", 
    "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest", 
    "version" : "1.0.1", 
    "engineVersion" : "3.0 rc0" 
}

 

project.manifest:

{ 
    "packageUrl" : "http://192.168.1.11:8000/res", 
    "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest", 
    "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest", 
    "version" : "1.0.1", 
    "engineVersion" : "3.0 rc0", 
    "assets" : { 
        "src/app.zip" : { 
            "md5" : "D07D260D8072F786A586A6A430D0E98B", 
            "compressed" : true 
        } 
    },

    "searchPaths" : [ 
    ] 
}

 

manifest這里使用了官方說明沒有提到的compressed,src/app.zip並沒有在初始打包的程序中,這個只是更新用的。指定了compressed=true,AssetsManager下載后會自動解壓這個文件,並保留這個文件。這樣就可以減少網絡傳輸的文件大小。

app.zip壓縮的是app.js,解壓后將覆蓋初始化安裝的app.js,從而實現了動態更新。

這里可以多次更新,不斷更新version號即可,每次AssetsManager會檢查文件是否存在、文件md5是否一致,如果不存在或者md5不一致都會重新下載。

 

2、無需重新打包發布,直接打開cocos2d程序,可以看到update的字樣,如果打開了logcat,也可以看到對應的日志。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM