123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- const fs = require('fs');
- const path = require('path');
- const crypto = require('crypto');
- const setting = require('./build-setting');
- const utils = require('./libs/utils');
- const assetsObfuscator = require('./assets-obfuscator');
- module.exports = (function (){
- var _instance;
- function AssetsHotUpdate (params) {
- return {
- _ready: false,
- _src: null,
- _dest: null,
- _manifest: {
- packageUrl: 'http://localhost/hot-update/',
- remoteManifestUrl: 'http://localhost/hot-update/project.manifest',
- remoteVersionUrl: 'http://localhost/hot-update/version.manifest',
- version: '300001',
- assets: {},
- searchPaths: []
- },
- init (actualPlatform) {
- this._ready = false;
- let assetsHotUpdate = `assetsHotUpdate`;
- let update = setting.getInstance().getItem(assetsHotUpdate);
- if (!update) { Editor.warn('缺少配置,跳过资源热更!'); return false; }
- if (!update.enable) { Editor.warn('未开启资源热更!'); return false; }
- let platform = update.platform || ''; // 平台配置
- let supportList = platform.split(',');
- if (!supportList.includes(actualPlatform)) {
- Editor.warn(actualPlatform, '平台不支持资源热更');
- return false;
- }
- let src = update.src;
- let dest = update.dest;
- let appVersion = update.appVersion; // 指定的代码版本号
- let hxCode = update.hxCode; // 指定的混淆码
- let resVersion = update.resVersion; // 指定的代码资源号
- let remoteUrl = update.remoteUrl;
- if (!src || !dest || !remoteUrl) {
- Editor.error('资源热更配置不满足');
- return false;
- }
- let cfg = setting.getInstance().getVersionConfig() || {};
- // 如果没有指定代码版本号就使用 VersionConfig.js 的代码版本号
- if (!resVersion || resVersion.length === 0) {
- appVersion = String(cfg.APP_VERSION) || '';
- }
- // 如果没有指定混淆码就使用 VersionConfig.js 的混淆码
- if (!hxCode || hxCode.length === 0) {
- hxCode = String(cfg.HX_CODE) || '';
- }
- // 如果没有指定代码资源号就使用 VersionConfig.js 的代码资源号
- if (!resVersion || resVersion.length === 0) {
- resVersion = String(cfg.RES_VERSION) || '';
- }
- this.appVersion = appVersion;
- this.hxCode = hxCode;
- this.resVersion = resVersion;
- Editor.log('代码版本号: ' + appVersion + '; 混淆Code: ' + hxCode + '; 代码资源号: ' + resVersion);
- this._src = path.join(Editor.Project.path, src);
- this._dest = path.join(Editor.Project.path, dest);
- if (fs.existsSync(this._dest)) {
- utils.rmdirSync(this._dest);
- }
- fs.mkdirSync(this._dest);
- this._manifest.version = resVersion;
- this._manifest.packageUrl = remoteUrl;
- this._manifest.remoteManifestUrl = remoteUrl + '/project.manifest';
- this._manifest.remoteVersionUrl = remoteUrl + '/version.manifest';
- this._manifest.assets = {};
- this._manifest.searchPaths = [];
- // 获取UUID
- let assetsdb = this.getAssetsdbPath(this._src);
- let projectManifestPath = this._src + '/project.manifest';
- utils.accessPath(projectManifestPath, (err)=> {
- if (err && err.code === 'ENOENT') {
- let assetsdbProjectManifestPath = assetsdb + '/project.manifest';
- utils.createProjectManifestAssets(assetsdbProjectManifestPath, remoteUrl, (err, results) => {
- if (err) {
- Editor.error(err);
- return false;
- }
- let result = results[0];
- this._projectManifestUUID = result.uuid;
- });
- } else {
- this._projectManifestUUID = Editor.assetdb._path2uuid[projectManifestPath];
- }
- });
- let versionManifestPath = this._src + '/version.manifest';
- utils.accessPath(versionManifestPath, (err)=> {
- let assetsdbVersionManifestPath = assetsdb + '/version.manifest';
- if (err && err.code === 'ENOENT') {
- utils.createVersionManifestAssets(assetsdbVersionManifestPath, remoteUrl, (err, results) => {
- if (err) {
- Editor.error(err);
- return false;
- }
- let result = results[0];
- this._versionManifestUUID = result.uuid;
- });
- } else {
- this._versionManifestUUID = Editor.assetdb._path2uuid[versionManifestPath];
- }
- });
- this._ignoreFileUuids = [];
- let ignores = update.ignores;
- if (ignores) {
- for (const aPath of ignores) {
- let fullpath = path.join(Editor.Project.path, aPath);
- let stat = fs.statSync(fullpath);
- if (stat.isDirectory()) {
- utils.findFileSync(fullpath, (filePath)=> {
- this.addIgnoreFile(filePath);
- });
- } else if (stat.isFile()) {
- this.addIgnoreFile(fullpath);
- }
- }
- }
- this._ready = true;
- return true;
- },
- isReady () {
- return this._ready;
- },
- addIgnoreFile (filePath) {
- let index = filePath.lastIndexOf('.');
- let ext = filePath.substr(index + 1);
- if (ext !== 'meta') {
- let uuid = Editor.assetdb._path2uuid[filePath];
- this._ignoreFileUuids.push(uuid);
- }
- },
- getAssetsdbPath (root) {
- let assetsdb = 'db://';
- let assetsIdx = root.indexOf('assets');
- if (assetsIdx !== -1) {
- assetsdb += root.substr(assetsIdx, root.length);
- } else {
- assetsdb += '/assets';
- }
- return assetsdb;
- },
- addHotUpdateSearchPaths (buildDest) {
- var root = path.normalize(buildDest);
- var url = path.join(root, 'main.js');
- let data = fs.readFileSync(url, 'utf8');
- if (data) {
- try {
- var newStr =
- ' // 编译助手追加代码 开始\n' +
- ' var hotUpdateSearchPaths = jsb.fileUtils.getWritablePath() + \'remote-assets\';\n' +
- ' var curVersionName = \'' + this.appVersion + '\';\n' +
- ' var curHxCode = \'' + this.hxCode + '\';\n' +
- ' var oldVersionName = cc.sys.localStorage.getItem(\'HOT_UPDATE_VERSION_NAME\');\n' +
- ' var oldHxCode = cc.sys.localStorage.getItem(\'HOT_UPDATE_HX_CODE\');\n' +
- ' if (curVersionName != oldVersionName || curHxCode != oldHxCode) {\n' +
- ' jsb.fileUtils.removeDirectory(hotUpdateSearchPaths);\n' +
- ' }\n' +
- ' var searchPaths = jsb.fileUtils.getSearchPaths();\n' +
- ' searchPaths.unshift(hotUpdateSearchPaths);\n' +
- ' jsb.fileUtils.setSearchPaths(searchPaths);\n' +
- ' // 编译助手追加代码 结束\n\n' +
- ' window.boot();';
- newStr = data.replace(' window.boot();', newStr);
- fs.writeFileSync(url, newStr);
- Editor.log('热更搜索路径写入' + url + '成功');
- } catch (error) {
- Editor.error('热更搜索路径成功写入' + url + '失败');
- }
- } else {
- Editor.error('读取' + url + '失败');
- }
- },
- getAssetsBuiledUrl (root, uuid) {
- if (!root || !uuid) {
- return;
- }
- let url;
- let dirname = uuid.substr(0, 2);
- let dirPath = path.join(root, 'res/raw-assets', dirname);
- let files = fs.readdirSync(dirPath);
- for (const fileName of files) {
- if (fileName.includes(uuid)) {
- url = path.join(dirPath, fileName);
- break;
- }
- }
- return url;
- },
- readBuildDest (root, dir, obj) {
- let stat = fs.statSync(dir);
- if (!stat.isDirectory()) {
- return;
- }
- let subpaths = fs.readdirSync(dir), subpath, size, md5, compressed, relative;
- for (let i = 0; i < subpaths.length; ++i) {
- if (subpaths[i][0] === '.') {
- continue;
- }
- subpath = path.join(dir, subpaths[i]);
- stat = fs.statSync(subpath);
- if (stat.isDirectory()) {
- this.readBuildDest(root, subpath, obj);
- } else if (stat.isFile()) {
- let hasIgnore = false;
- for (const uuid of this._ignoreFileUuids) {
- let include = subpath.includes(uuid);
- if (include) {
- hasIgnore = true;
- break;
- }
- }
- if (hasIgnore) {
- continue;
- }
- // Size in Bytes
- size = stat['size'];
- md5 = crypto.createHash('md5').update(fs.readFileSync(subpath)).digest('hex');
- compressed = path.extname(subpath).toLowerCase() === '.zip';
- relative = path.relative(root, subpath);
- relative = relative.replace(/\\/g, '/');
- relative = encodeURI(relative);
- obj[relative] = {
- 'size': size,
- 'md5': md5
- };
- if (compressed) {
- obj[relative].compressed = true;
- }
- }
- }
- },
- generateManifest (buildDest, callback) {
- let projectManifestUUID = this._projectManifestUUID;
- let versionManifestUUID = this._versionManifestUUID;
- if (assetsObfuscator.getInstance().isReady()) {
- let mima = assetsObfuscator.getInstance().getMima();
- if (this._projectManifestUUID) {
- projectManifestUUID = assetsObfuscator.getInstance().getNewName(mima, this._projectManifestUUID);
- }
- if (this._versionManifestUUID) {
- Editor.log('this._versionManifestUUID', this._versionManifestUUID);
- versionManifestUUID = assetsObfuscator.getInstance().getNewName(mima, this._versionManifestUUID);
- Editor.log('versionManifestUUID', versionManifestUUID);
- }
- }
- let projectManifestURL = this.getAssetsBuiledUrl(buildDest, projectManifestUUID);
- if (!projectManifestURL) {
- Editor.error('生成project.manifest失败');
- return;
- }
- let versionManifestURL = this.getAssetsBuiledUrl(buildDest, versionManifestUUID);
- if (!versionManifestURL) {
- Editor.error('生成version.manifest失败');
- return;
- }
- let destProjectManifestURL = path.join(this._dest, 'project.manifest');
- let destVersionManifestURL = path.join(this._dest, 'version.manifest');
- this.readBuildDest(buildDest, path.join(buildDest, 'src'), this._manifest.assets);
- this.readBuildDest(buildDest, path.join(buildDest, 'res'), this._manifest.assets);
- try {
- fs.writeFileSync(projectManifestURL, JSON.stringify(this._manifest));
- fs.writeFileSync(destProjectManifestURL, JSON.stringify(this._manifest));
- Editor.log('写入project.manifest成功', projectManifestURL);
- let md5 = crypto.createHash('md5').update(fs.readFileSync(destProjectManifestURL)).digest('hex');
- Editor.warn('project.manifest md5 = ', md5);
- delete this._manifest.assets;
- delete this._manifest.searchPaths;
- fs.writeFileSync(versionManifestURL, JSON.stringify(this._manifest));
- fs.writeFileSync(destVersionManifestURL, JSON.stringify(this._manifest));
- Editor.log('写入version.manifest成功', versionManifestURL);
- callback();
- } catch (error) {
- callback(error);
- }
- },
- copyAssets (buildDest) {
- // fs.copyFileSync(path.join(buildDest, 'main.js'), path.join(this._dest, 'main.js'));
- // fs.copyFileSync(path.join(buildDest, 'project.json'), path.join(this._dest, 'project.json'));
- // utils.copyFolder(path.join(buildDest, 'jsb-adapter'), path.join(this._dest, 'jsb-adapter'));
- utils.copyFolder(path.join(buildDest, 'src'), path.join(this._dest, 'src'));
- utils.copyFolder(path.join(buildDest, 'res'), path.join(this._dest, 'res'));
- // let debuggingPath = path.join(buildDest, 'js backups (useful for debugging)');
- // if (fs.existsSync(debuggingPath)) {
- // utils.copyFolder(debuggingPath, path.join(this._dest, 'js backups (useful for debugging)'));
- // }
- }
- };
- }
- return {
- getInstance (params) {
- if (!_instance){
- _instance = AssetsHotUpdate(params);
- }
- return _instance;
- }
- };
- })();
|