// Learn TypeScript:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class CheckUpdate extends cc.Component {
@property(cc.Label)
label: cc.Label = null;
private VERSION_KEY = "HotUpdateVersion";
private _localVersion = "1";
private _remoteVersion = "1";
private _updating = false;
private _canRetry = false;
private _storagePath = '';
private _remotePackageUrl = null!;
private _am: jsb.AssetsManager = null!;
// private _checkListener = null;
private _updateListener = null;
private versionCompareHandle: (versionA: string, versionB: string) => number = null!;
onLoad() {
console.log('33333333333333333333');
this.initAsync();
}
async initAsync(){
let t = this;
if (!jsb) {
return;
}
t._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'remote-assets');
console.log('Storage path for remote asset : ' + t._storagePath);
t._localVersion = localStorage.getItem(t.VERSION_KEY) || "1";
this.saveSearchPaths();
t.versionCompareHandle = function (versionA: string, versionB: string) {
console.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
var vA = versionA.split('.');
var vB = versionB.split('.');
for (var i = 0; i < vA.length; ++i) {
var a = parseInt(vA[i]);
var b = parseInt(vB[i] || '0');
if (a === b) {
continue;
}
else {
return a - b;
}
}
if (vB.length > vA.length) {
return -1;
}
else {
return 0;
}
// return t._localVersion!=t._remoteVersion? -1:0;
};
let remote_asset_url = "http://192.168.1.206:8888/remote-assets/test/"
let remoteVersionFile = remote_asset_url+"version.txt?t=" + Date.now();
await new Promise((resolve, reject) => {
cc.assetManager.loadRemote<cc.TextAsset>(remoteVersionFile, (err, data) => {
if (err) {
console.error("加载版本控制文件失败:",remoteVersionFile, err);
t.updatelabel("加载版本控制文件失败:"+remoteVersionFile);
reject(err);
} else {
// data 是一个 TextAsset,需取 .text
t._remoteVersion = data.text.trim(); // 注意 trim()
console.log("remoteVersion",t._remoteVersion);
resolve(1);
}
});
});
//manifest 结构
// var customManifestStr = JSON.stringify({
// "packageUrl": "http://192.168.55.13:5502/remote-assets/",
// "remoteManifestUrl": "http://192.168.55.13:5502/remote-assets/project.manifest",
// "remoteVersionUrl": "http://192.168.55.13:5502/remote-assets/version.manifest",
// "version": "1.0.0",
// "assets": {
// "src/application.js": {
// "size": 5514,
// "md5": "d09753aaed7c55c4566cecf766cbc5c3"
// },
// },
// "searchPaths": []
// });
t._remotePackageUrl = remote_asset_url + t._remoteVersion+"/";
console.log("remotePackageUrl",t._remotePackageUrl);
var searchPaths = jsb.fileUtils.getSearchPaths();
console.log("getSearchPaths111",searchPaths);
//经测试下面这两种写法效果一样
t._am = new jsb.AssetsManager("", t._storagePath, t.versionCompareHandle);
// t._am = new jsb.AssetsManager(t._remotePackageUrl+"project.manifest", t._storagePath, t.versionCompareHandle);
// Setup the verification callback, but we don't have md5 check function yet, so only print some message
// Return true if the verification passed, otherwise return false
t._am.setVerifyCallback(function (path: string, asset: any) {
// When asset is compressed, we don't need to check its md5, because zip file have been deleted.
var compressed = asset.compressed;
// Retrieve the correct md5 value.
var expectedMD5 = asset.md5;
// asset.path is relative path and path is absolute.
var relativePath = asset.path;
// The size of asset file, but this value could be absent.
var size = asset.size;
if (compressed) {
t.updatelabel("Verification passed : " + relativePath);
return true;
}
else {
t.updatelabel("Verification passed : " + relativePath + ' (' + expectedMD5 + ')');
return true;
}
});
console.log('Hot update is ready, please check or directly update.');
t.hotUpdate();
}
private saveSearchPaths(){
const mainBundlePath = '\@assets/';
var searchPaths = {
updatePath:this._storagePath,
mainBundlePath:mainBundlePath
}
localStorage.setItem("HotUpdateSearchPaths", JSON.stringify(searchPaths));
}
onDestroy() {
if (this._updateListener) {
this._am.setEventCallback(null!);
this._updateListener = null;
}
}
loadLocalManifest():boolean{
let t = this;
if (t._am.getState() === jsb.AssetsManager.State.UNINITED) {
let localManifestPath = t._storagePath + `/project.manifest`;
if (!jsb.fileUtils.isFileExist(localManifestPath)){
localManifestPath = cc.url.raw('resources/native/project.manifest')
}
console.log("initial Manifest Path",localManifestPath)
const manifestStr = jsb.fileUtils.getStringFromFile(localManifestPath);
if (manifestStr) {
const newManifest = t.getNewManifest(manifestStr, t._storagePath);
t._am.loadLocalManifest(newManifest,t._storagePath);
}else {
t.updatelabel('Failed to read initial manifest');
return false;
}
}
if (!t._am.getLocalManifest() || !t._am.getLocalManifest().isLoaded()) {
t.updatelabel('Failed to load local manifest ...');
return false;
}
return true;
}
private getNewManifest(manifestStr:string,storagePath):jsb.Manifest{
let t = this;
// let json = JSON.parse(manifestStr);
// json.packageUrl = t._remotePackageUrl;
// json.remoteManifestUrl = t._remotePackageUrl+"project.manifest";
// json.remoteVersionUrl = t._remotePackageUrl+"version.manifest";
// console.log("manifest packageUrl",json.packageUrl);
// console.log("manifest remoteManifestUrl",json.remoteManifestUrl);
// console.log("manifest remoteVersionUrl",json.remoteVersionUrl);
// return new jsb.Manifest(JSON.stringify(json), storagePath)
return new jsb.Manifest(manifestStr, storagePath)
}
hotUpdate() {
let t = this;
t.updatelabel('start hotupdate...');
if (t._am && !t._updating) {
t.updatelabel('start hotupdate111');
let inited = t.loadLocalManifest();
if(!inited){
console.log("checkUpdate","loadLocalManifest失败");
return;
}
t._am.setEventCallback(t.updateCb.bind(t));
t._am.update();
t._updating = true;
}else{
console.log("hotUpdate failed","t._am=",t._am,"_updating="+t._updating)
}
}
updateCb(event: jsb.EventAssetsManager) {
let t = this;
var needRestart = false;
var failed = false;
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
console.log("updateCb failed: ","ERROR_NO_LOCAL_MANIFEST", event.getMessage());
this.updatelabel('No local manifest file found, hot update skipped.');
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
const percent = event.getPercentByFile();//event.getPercent();
if(percent && percent > 0){
console.log("updateCb : ", `${(percent * 100).toFixed(2)}%`);
this.updatelabel(`${(percent * 100).toFixed(2)}%`);
}
//数量进度
if(event.getTotalFiles()>0){
console.log("下载进度", event.getDownloadedFiles() + ' / ' + event.getTotalFiles());
}
var msg = event.getMessage();
if (msg) {
this.updatelabel('Updated file: ' + msg);
// cc.log(event.getPercent()/100 + '% : ' + msg);
}
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
console.log("updateCb failed: ","ERROR_DOWNLOAD_MANIFEST", event.getMessage());
this.updatelabel('ERROR_DOWNLOAD_MANIFEST');
failed = true;
break;
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
console.log("updateCb failed: ","ERROR_PARSE_MANIFEST", event.getMessage());
this.updatelabel('ERROR_PARSE_MANIFEST');
failed = true;
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
this.updatelabel('ALREADY_UP_TO_DATE');
console.log("updateCb","********now is latest********");
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
this.updatelabel('UPDATE_FINISHED');
console.log("updateCb","********finished********");
needRestart = true;
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
this.updatelabel('UPDATE_FAILED');
console.log("updateCb failed: ","UPDATE_FAILED", event.getMessage());
this._updating = false;
this._canRetry = true;
break;
case jsb.EventAssetsManager.ERROR_UPDATING:
console.log("updateCb failed: ","ERROR_UPDATING", event.getAssetId() + ', ' + event.getMessage());
this.updatelabel('ERROR_UPDATING');
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
console.log("updateCb failed: ","ERROR_DECOMPRESS", event.getMessage());
this.updatelabel('ERROR_DECOMPRESS');
break;
default:
console.log("updateCb: ","unknown", event.getEventCode(), event.getMessage());
break;
}
if (failed) {
this._am.setEventCallback(null!);
this._updateListener = null;
this._updating = false;
}
if (needRestart) {
this._am.setEventCallback(null!);
this._updateListener = null;
t._localVersion = t._remoteVersion;
localStorage.setItem(t.VERSION_KEY, t._localVersion);
// restart game.
setTimeout(() => {
console.log("restart cocos");
cc.game.restart();
}, 1000)
}
}
retry() {
let t = this;
if (!this._updating && this._canRetry) {
this._canRetry = false;
t.updatelabel('Retry failed Assets...');
this._am.downloadFailedAssets();
}
}
private updatelabel(str: string){
if (this.label != null) {
this.label.string = str;
}
}
}