fy-nativebuilder
Version:
laya native builder for fygame.
265 lines (264 loc) • 14.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Builder = void 0;
var cp = require("child_process");
var process_1 = require("process");
var fs = require("fs-extra");
var path = require("path");
var _ = require("lodash");
var tkit = __importStar(require("./tkit/Tkit"));
var Builder = /** @class */ (function () {
function Builder() {
}
Builder.prototype.start = function (options) {
var _a = options.platform.split(':'), projName = _a[0], pf = _a[1], publishMode = _a[2];
// 先读取默认环境配置
var envCfg = fs.readJSONSync(path.join(__dirname, 'assets/localEnv.json'), { encoding: 'utf-8' });
if (options.localEnv) {
// 再读取本地环境配置
var localEnv = fs.readJSONSync(options.localEnv, { encoding: 'utf-8' });
envCfg = _.assign(envCfg, localEnv);
}
process.chdir(options.project);
var projectFilesRoot = path.join(options.project, 'build/projectfiles', pf);
// 清空patch文件夹
var patchPath = path.join(projectFilesRoot, 'patch');
fs.ensureDirSync(patchPath);
fs.emptyDirSync(patchPath);
var cfgPath = path.join(projectFilesRoot, 'common/cfg.json');
var cfgDscb = fs.readJSONSync(cfgPath, { encoding: 'utf-8' });
var cfgJson = cfgDscb[options.gameid];
if (!cfgJson) {
console.error('no cfg found: %d', options.gameid);
}
// 读取全局配置
var globalCfg = cfgDscb['global'];
// 合并配置
cfgJson = _.assign(globalCfg, cfgJson);
// 替换配置中的local变量
tkit.FillJsonValues(cfgJson, envCfg);
console.log(cfgJson);
// 先打layadcc
var builtInCacheRoot;
if (options.dcc) {
var dccOutPath = path.join(cfgJson.output_path, cfgJson.projName, 'dcc');
fs.ensureDirSync(dccOutPath);
fs.emptyDirSync(dccOutPath);
var dccCmd = 'layadcc ' + cfgJson.res_path + ' -cache -url ' + cfgJson.url + ' -cout ' + path.resolve(dccOutPath);
console.log('start layadcc: %s', dccCmd);
var startAt = _.now();
console.log(cp.execSync(dccCmd, { encoding: 'utf-8' }));
console.log('layadcc finished, %d s costed.', Math.floor(_.now() - startAt) / 1000);
var dccCacheFilesRoot = path.join(dccOutPath, 'cache', this.getCacheFolder(cfgJson.url));
builtInCacheRoot = path.join(cfgJson.output_path, cfgJson.projName, 'builtin');
fs.ensureDirSync(builtInCacheRoot);
fs.emptyDirSync(builtInCacheRoot);
// 拷贝dcc资源到增量包
var StartLineNum = 3;
var resCfgRootParent = path.join(envCfg.h5BuildConfigRoot, projName, pf);
var resCfgRoot = path.join(resCfgRootParent, publishMode);
var savedFiletablePath = path.join(resCfgRoot, 'filetable.txt');
if (fs.existsSync(resCfgRootParent)) {
tkit.svn.revert(resCfgRoot);
tkit.svn.update(resCfgRoot);
}
else {
fs.mkdirpSync(resCfgRoot);
fs.writeFileSync(savedFiletablePath, '', 'utf-8');
tkit.svn.add(resCfgRootParent);
tkit.svn.commit(resCfgRootParent, 'init commit by Builder');
}
// 先读取上次的dcc资源列表
var savedFileMap = {};
if (fs.existsSync(savedFiletablePath)) {
var savedFiletableLines = fs.readFileSync(savedFiletablePath, 'utf-8').split(/[\r\n]+/);
for (var i = StartLineNum, len = savedFiletableLines.length; i < len; i++) {
var saveFilePair = savedFiletableLines[i].split(/\s+/);
savedFileMap[saveFilePair[0]] = saveFilePair[1];
}
}
else {
fs.writeFileSync(savedFiletablePath, '', 'utf-8');
tkit.svn.add(savedFiletablePath);
tkit.svn.commit(savedFiletablePath, 'init commit by Builder');
}
// 遍历dcc资源,将新资源拷贝到增量包
var filetablePath = path.join(dccCacheFilesRoot, 'filetable.txt');
var filetableLines = fs.readFileSync(filetablePath, 'utf-8').split(/[\r\n]+/);
for (var i = StartLineNum, len = filetableLines.length; i < len; i++) {
var cacheFileName = filetableLines[i].split(/\s+/)[0];
if (!savedFileMap[cacheFileName]) {
fs.copyFileSync(path.join(dccCacheFilesRoot, cacheFileName), path.join(patchPath, cacheFileName));
}
}
// 拷贝几个dcc文件到增量包
var staticFiles = ['allfiles.txt', 'assetsid.txt', 'filetable.bin', 'filetable.txt'];
for (var _i = 0, staticFiles_1 = staticFiles; _i < staticFiles_1.length; _i++) {
var filename = staticFiles_1[_i];
fs.copyFileSync(path.join(dccCacheFilesRoot, filename), path.join(patchPath, filename));
}
// 保存本次的filetable.txt,将在资源外发时上传svn
fs.copyFileSync(filetablePath, savedFiletablePath);
// 筛选需要打进包内的资源
if (cfgJson.builtin) {
var builtinPath = path.join(projectFilesRoot, cfgJson.builtin);
var builtinLines = fs.readFileSync(builtinPath, 'utf-8').split(/[\r\n]+/);
var builtinCnt = builtinLines.length;
if (builtinCnt > 0) {
var allfilesPath = path.join(dccCacheFilesRoot, 'allfiles.txt');
var allfilesLines = fs.readFileSync(allfilesPath, 'utf-8').split(/[\r\n]+/);
// builtin.txt按照文件顺序写的,也就是说和allfiles.txt顺序是一致的,动态调整循环匹配的起始行,比每次都从第一个进行匹配效率高
var startMatchIdx = 0;
// allfiles.txt前3行校验用
for (var i = 0, len = allfilesLines.length; i < len; i++) {
var oneFile = allfilesLines[i];
var needBuiltin = false;
var s = startMatchIdx;
for (var j = s; j < builtinCnt; j++) {
if (oneFile.startsWith(builtinLines[j])) {
needBuiltin = true;
startMatchIdx = j;
break;
}
}
if (!needBuiltin) {
for (var j = 0; j < s; j++) {
if (oneFile.startsWith(builtinLines[j])) {
needBuiltin = true;
break;
}
}
}
if (needBuiltin) {
var cacheFileName = filetableLines[i + StartLineNum].split(/\s+/)[0];
var cacheFilePath = path.join(dccCacheFilesRoot, cacheFileName);
fs.copyFileSync(cacheFilePath, path.join(builtInCacheRoot, cacheFileName));
fs.copyFileSync(cacheFilePath, path.join(patchPath, cacheFileName));
}
}
}
}
}
// 输出android工程
if (options.buildApk) {
var androidProjPath = path.join(cfgJson.output_path, cfgJson.projName, cfgJson.platform);
fs.removeSync(androidProjPath);
// cmd = 'layanative createapp [-f res_path] [--path output_path] [-s sdk_path | -v version] [-p all|ios|android_eclipse|android_studio] [-t 0|1|2] [-u url] [-n project_name] [-a app_name] [--package_name package_name]'
var nativeCmd = 'layanative createapp --path ' + cfgJson.output_path + ' -v ' + cfgJson.sdkver + ' -p ' + cfgJson.platform + ' -u ' + cfgJson.url + ' -n ' + cfgJson.projName + ' -a ' + cfgJson.appName + ' --package_name ' + cfgJson.package_name + ' -d ' + cfgJson.dememsionType;
console.log('start create app: %s', nativeCmd);
var startAt = _.now();
console.log(cp.execSync(nativeCmd, { encoding: 'utf-8' }));
console.log('createapp finished, %d s costed.', Math.floor((_.now() - startAt) / 1000));
// 资源替换
var projectReplaces = ['default', options.gameid + ''];
for (var _b = 0, projectReplaces_1 = projectReplaces; _b < projectReplaces_1.length; _b++) {
var oneReplace = projectReplaces_1[_b];
var projectReplaceRoot = path.join(projectFilesRoot, 'android_studio', oneReplace);
if (fs.existsSync(projectReplaceRoot)) {
console.log('replace project files from %s to %s', projectFilesRoot, androidProjPath);
fs.copySync(projectReplaceRoot, androidProjPath);
}
else {
console.log('replace root not exists: %s', projectReplaceRoot);
}
}
// 读取版本号
var oldVer = 0;
var versionFile = path.join(projectFilesRoot, 'version.txt');
if (fs.existsSync(versionFile)) {
oldVer = Number(fs.readFileSync(versionFile, 'utf-8'));
}
var newVer = oldVer + 1;
var newVerName = '1.0.0.' + newVer;
fs.writeFileSync(versionFile, newVer.toString(), 'utf-8');
// 修改版本号
var manifestFile = path.join(androidProjPath, 'app/src/main/AndroidManifest.xml');
var manifestContent = fs.readFileSync(manifestFile, 'utf-8');
manifestContent = manifestContent.replace(/(?<=versionCode=")\d+(?=")/, newVer.toString());
manifestContent = manifestContent.replace(/(?<=versionName=")\S+(?=")/, newVerName);
// 覆盖gradle脚本,增加签名信息、扩大jvm内存
var appGradleContent = fs.readFileSync(path.join(__dirname, 'assets/build.gradle'), 'utf-8');
for (var rkey in cfgJson) {
appGradleContent = appGradleContent.replace('{' + rkey + '}', cfgJson[rkey]);
}
var appGradlePath = path.join(androidProjPath, 'app/build.gradle');
fs.writeFileSync(appGradlePath, appGradleContent, 'utf-8');
if (options.dcc) {
// 拷贝包内资源
fs.copySync(builtInCacheRoot, path.join(androidProjPath, 'app/src/main/assets/cache', this.getCacheFolder(cfgJson.url)));
}
// 拷贝local.properties、gradle.properties
var coverFiles = ['local.properties', 'gradle.properties'];
for (var _c = 0, coverFiles_1 = coverFiles; _c < coverFiles_1.length; _c++) {
var oneCoverFile = coverFiles_1[_c];
var coverContent = fs.readFileSync(path.join(__dirname, 'assets', oneCoverFile), 'utf-8');
for (var envkey in envCfg) {
coverContent = coverContent.replace('{' + envkey + '}', envCfg[envkey]);
}
fs.writeFileSync(path.join(androidProjPath, oneCoverFile), coverContent, 'utf-8');
}
// 打包
process.chdir(androidProjPath);
console.log('now we are %s', process.cwd());
var gradleCmd = path.join(envCfg.gradleToolPath, 'gradlew') + ' assembleRelease';
console.log('start gradle: %s', gradleCmd);
startAt = _.now();
console.log(cp.execSync(gradleCmd, { encoding: 'utf-8' }));
console.log('assemble finished, %d s costed.', Math.floor((_.now() - startAt) / 1000));
process.chdir(options.project);
// 拷贝apk到增量包
var apkPath = path.join(androidProjPath, 'app/build/outputs/apk/release/app-release.apk');
var targetApkPath = path.join(patchPath, 'apk', cfgJson.package_name + '.v' + newVerName + '.apk');
this.copyFileEnsureExists(apkPath, targetApkPath);
}
};
/**这段代码摘自layadcc源码 */
Builder.prototype.getCacheFolder = function (url) {
var cacheOut = url;
cacheOut = cacheOut.replace('http://', '');
var index = cacheOut.indexOf('?');
if (index > 0) {
cacheOut = cacheOut.substring(0, index);
}
index = cacheOut.lastIndexOf('/');
if (index > 0) {
cacheOut = cacheOut.substring(0, index);
}
cacheOut = cacheOut.replace(/:/g, '.');
cacheOut = cacheOut.replace(/\\/g, '_');
cacheOut = cacheOut.replace(/\//g, '_');
return cacheOut;
};
Builder.prototype.copyFileEnsureExists = function (src, dest) {
if (!fs.existsSync(src)) {
console.error('Could not find apk: %s!', src);
process_1.exit(1);
}
var dirname = path.dirname(dest);
if (!fs.existsSync(dirname)) {
fs.mkdirpSync(dirname);
}
fs.copyFileSync(src, dest);
};
return Builder;
}());
exports.Builder = Builder;