manifest-gen.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. const Path=require("path"),Fs=require("fire-fs"),Encrypt=Editor.require("packages://encrypt-tool/panel/index.js"),CfgUtil=Editor.require("packages://hot-update-tools/core/CfgUtil.js"),Util=Editor.require("packages://hot-update-tools/core/Util.js"),OutPut=Editor.require("packages://hot-update-tools/core/OutPut.js"),GoogleAnalytics=Editor.require("packages://hot-update-tools/core/GoogleAnalytics.js"),Electron=require("electron");
  2. const pngBufferHeader = {
  3. bufBegin: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
  4. bufEnd: [0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82],
  5. suffix: '.png'
  6. };
  7. Vue.component("manifest-gen",{
  8. template:Fs.readFileSync(Editor.url("packages://hot-update-tools/panel/manifest-gen.html"),"utf-8"),
  9. mixins:[Editor.require("packages://hot-update-tools/panel/mixin.js")],
  10. data:()=>(
  11. {
  12. selectDestType:"",
  13. isUsedEncrypt:!1,
  14. version:"",
  15. serverRootDir:"",
  16. remoteServerVersion:"",
  17. hotAddressArray:[],
  18. resourceRootDir:"",
  19. genManifestDir:"",
  20. isShowUseAddrBtn:!1,
  21. isShowDelAddrBtn:!1,
  22. encryptSign: "",
  23. encryptPass: "",
  24. signKey: "civiTool",
  25. passWord: "civiTool2020",
  26. engineVersion:"",
  27. rootPath: "",
  28. cfgPath: "",
  29. totalPng: [],
  30. hasEncrypt: 0,
  31. hasBuildProj: !1,
  32. }
  33. ),
  34. computed:{
  35. isValidResDir(){
  36. return!(!this.resourceRootDir||!Fs.existsSync(this.resourceRootDir))
  37. }
  38. },
  39. created(){
  40. this.$nextTick(()=>{
  41. let e=CfgUtil.cfgData;
  42. e&&(this.selectDestType=e.selectDestType,this.isUsedEncrypt=e.isUsedEncrypt,this.version=e.version,this.serverRootDir=e.serverRootDir,this.resourceRootDir=e.resourceRootDir,this.hotAddressArray=e.hotAddressArray||[]),this.genManifestDir=OutPut.manifestDir,this._getRemoteServerVersion(),this._initResourceBuild()
  43. })
  44. },
  45. methods:{
  46. _initResourceBuild(){
  47. let e=Editor.Project.path,t=Path.join(e,"local/builder.json");
  48. if(Fs.existsSync(t)){
  49. let s=JSON.parse(Fs.readFileSync(t,"utf-8")),i=s.buildPath,r=Path.join(e,i),o=Path.join(r,`jsb-${s.template}`);
  50. if(!Fs.existsSync(o)){
  51. let e=Path.join(r,s.platform);Fs.existsSync(e)&&(o=e)
  52. }
  53. this._checkResourceRootDir(o)
  54. }else
  55. this.log("发现没有构建项目, 使用前请先构建项目!")
  56. //初始化加密资源
  57. this.initPluginCfg();
  58. },
  59. _isVersionPass(e,t){
  60. if(void 0===e||null===e||void 0===t||null===t)return!1;
  61. let s=e.split("."),i=t.split("."),r=s.length>i.length?s.length:i.length;
  62. for(let e=0;e<r;e++){
  63. let t=s[e],r=i[e];
  64. if(void 0===t&&void 0!==r)return!1;
  65. if(void 0!==t&&void 0===r)return!0;
  66. if(t&&r&&parseInt(t)>parseInt(r))return!0
  67. }
  68. return!1
  69. },
  70. _updateShowUseAddrBtn(){
  71. let e=this.$els.address.value;
  72. this.serverRootDir===e&&(this.isShowUseAddrBtn=!1)
  73. },
  74. _updateShowEncryptInfo() {
  75. if(this.isUsedEncrypt==1) {
  76. this.encryptSign = "签名:"+this.signKey;
  77. this.encryptPass = "密码:"+this.passWord;
  78. }
  79. },
  80. _addHotAddress(e){
  81. let t=!0;
  82. for(let s=0;s<this.hotAddressArray.length;s++){
  83. if(this.hotAddressArray[s]===e){
  84. t=!1;
  85. break
  86. }
  87. }
  88. t&&(this.hotAddressArray.push(e),this.log("[HotAddress]历史记录添加成功:"+e))
  89. },
  90. _getRemoteServerVersion(){
  91. if(this.serverRootDir.length<=0)return;
  92. this.remoteServerVersion=null;
  93. let e=this.serverRootDir+"/version.manifest",t=new XMLHttpRequest;
  94. t.onreadystatechange=(()=>{
  95. if(4===t.readyState&&t.status>=200&&t.status<400){
  96. let e=t.responseText,s=null;
  97. try{
  98. s=JSON.parse(e)
  99. }
  100. catch(e){
  101. return void this.log("获取远程版本号失败!")
  102. }
  103. this.remoteServerVersion=s.version
  104. }else t.status
  105. }),t.open("get",e,!0),t.setRequestHeader("If-Modified-Since","0"),t.send()
  106. },
  107. onClickGenCfg(e){
  108. GoogleAnalytics.eventCustom("GenManifest"),!this.version||this.version.length<=0?this.log("[生成] 版本号未填写"):!this.serverRootDir||this.serverRootDir.length<=0?this.log("[生成] 服务器地址未填写"):0!==this.resourceRootDir.length?this._checkResourceRootDir(this.resourceRootDir)&&(!this.genManifestDir||this.genManifestDir.length<=0?this.log("[生成] manifest文件生成地址未填写"):Fs.existsSync(this.genManifestDir)?(this._saveConfig(),this.onDoEncrypt(this.version,this.serverRootDir,this.resourceRootDir,this.genManifestDir)):this.log("[生成] manifest存储目录不存在: "+this.genManifestDir)):this.log("[生成] 请先指定 <build项目资源文件目录>")
  109. },
  110. onClickOpenVersionDir(){this.openDir(OutPut.versionsDir+'/'+this.selectDestType)},
  111. onOpenManifestDir(){this.openDir(this.genManifestDir)},
  112. onOpenResourceDir(){this.openDir(this.resourceRootDir)},
  113. onSelectResourceRootDir(){
  114. let e=Editor.Dialog.openFile({title:"选择构建后的根目录",defaultPath:Editor.projectInfo.path,properties:["openDirectory"]});
  115. if(-1!==e){
  116. let t=e[0];
  117. this._checkResourceRootDir(t)&&(this.resourceRootDir=t,this._saveConfig())
  118. }
  119. },
  120. onBtnClickDelSelectedHotAddress(){
  121. let e=this.$els.address.value;
  122. if(this.hotAddressArray.length>0){
  123. let t=!1;
  124. for(let s=0;s<this.hotAddressArray.length;){
  125. let i=this.hotAddressArray[s];
  126. i===e?(this.hotAddressArray.splice(s,1),t=!0,this.log("删除历史地址成功: "+i)):s++
  127. }
  128. t&&(this.isShowDelAddrBtn=!1,this.isShowUseAddrBtn=!1,this._saveConfig())
  129. }else this.log("历史地址已经为空")
  130. },
  131. onBtnClickUseSelectedHotAddress(){
  132. this.$els;
  133. let e=this.$els.address.value;
  134. this.serverRootDir=e,this.onInPutUrlOver(),this._updateShowUseAddrBtn()
  135. },
  136. onClickUse(){
  137. this.log("开启加密选项")
  138. this.isUsedEncrypt = 1;
  139. this._updateShowEncryptInfo();
  140. },
  141. onClickNotUse() {
  142. this.log("关闭加密选项")
  143. this.isUsedEncrypt = !1;
  144. },
  145. onBtnClickTest(){
  146. this.onChangeSelectType("Test");
  147. },
  148. onBtnClickBeta(){
  149. this.onChangeSelectType("Beta");
  150. },
  151. onBtnClickRelease(){
  152. this.onChangeSelectType("Release");
  153. },
  154. onChangeSelectType(e) {
  155. this.selectDestType = e;
  156. let h=OutPut.versionsDir+'/'+this.selectDestType;
  157. if(!Fs.existsSync(h)) {
  158. this.log(e+"文件夹不存在,自动创建文件夹!!!");
  159. Fs.mkdir(h,()=>{});
  160. }
  161. let d = h+'/UnZip/';
  162. if(!Fs.existsSync(d)) {
  163. this.log("UnZip文件夹不存在,自动创建文件夹!!!");
  164. Fs.mkdir(d,()=>{});
  165. }
  166. this._saveConfig();
  167. },
  168. onChangeSelectHotAddress(e){
  169. GoogleAnalytics.eventCustom("ChangeSelectHotAddress"),this.isShowUseAddrBtn=!0,this.isShowDelAddrBtn=!0,this._updateShowUseAddrBtn()
  170. },
  171. userLocalIP(){
  172. GoogleAnalytics.eventCustom("useLocalIP");
  173. let e=Editor.require("packages://hot-update-tools/core/Util.js").getLocalIP();
  174. e.length>0&&(this.serverRootDir="http://"+e,this.onInPutUrlOver(null))
  175. },
  176. onInPutUrlOver(e){
  177. let t=this.serverRootDir;
  178. if("http://"===t||"https://"===t||"http"===t||"https"===t||"http:"===t||"https:"===t)return;
  179. let s=t.indexOf("http://"),i=t.indexOf("https://");
  180. if(-1===s&&-1===i){
  181. /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/.test(t)||(this.log(t+" 不是以http://https://开头,或者不是网址, 已经自动修改"),this.serverRootDir="http://"+this.serverRootDir,this._getRemoteServerVersion())
  182. }else this._getRemoteServerVersion();
  183. this._addHotAddress(this.serverRootDir),this._updateShowUseAddrBtn(),this._saveConfig()
  184. },
  185. _saveConfig(){
  186. let e={selectDestType:this.selectDestType,isUsedEncrypt:this.isUsedEncrypt,version:this.version,serverRootDir:this.serverRootDir,resourceRootDir:this.resourceRootDir,genManifestDir:OutPut.manifestDir,localServerPath:this.localServerPath,hotAddressArray:this.hotAddressArray};
  187. CfgUtil.saveConfig(e)
  188. },
  189. onInputVersionOver(){
  190. let e=CfgUtil.cfgData.genVersion,t=(CfgUtil.cfgData.buildTime,CfgUtil.cfgData.genTime,this.remoteServerVersion);
  191. null!==t&&void 0!==t&&(this._isVersionPass(this.version,t)?(this.log("上次构建时版本号: "+e),this._isVersionPass(this.version,e)?this.log("版本通过验证!"):this.log("[Warning] 要构建的版本低于上次构建版本: "+this.version+"<="+e)):this.log("[Warning] version 填写的版本低于远程版本")),this._saveConfig()
  192. },
  193. onStopTouchEvent(e){e.preventDefault(),e.stopPropagation()},
  194. onBtnClickHelpDoc(){
  195. GoogleAnalytics.eventDoc();
  196. Electron.shell.openExternal("https://tidys.github.io/plugin-docs-oneself/docs/hot-update-tools/")
  197. },
  198. onBtnClickTellMe(){
  199. GoogleAnalytics.eventQQ();
  200. Electron.shell.openExternal("http://wpa.qq.com/msgrd?v=3&uin=774177933&site=qq&menu=yes")
  201. },
  202. _genVersion(e,t,s,i){
  203. this.log("[Build] 开始生成manifest配置文件....");
  204. let r={version:e,packageUrl:t,remoteManifestUrl:"",remoteVersionUrl:"",assets:{},searchPaths:[]};"/"===t[t.length-1]?(r.remoteManifestUrl=t+"project.manifest",r.remoteVersionUrl=t+"version.manifest"):(r.remoteManifestUrl=t+"/project.manifest",r.remoteVersionUrl=t+"/version.manifest");
  205. let o=i,n=s,l=(e,t)=>{
  206. let s=Fs.statSync(e);
  207. if(!s.isDirectory())return;
  208. let i,r,o,a,h,d=Fs.readdirSync(e);
  209. for(let c=0;c<d.length;++c)
  210. "."!==d[c][0]&&(i=Path.join(e,d[c]),(s=Fs.statSync(i)).isDirectory()?l(i,t):s.isFile()&&(r=s.size,o=require("crypto").createHash("md5").update(Fs.readFileSync(i)).digest("hex"),a=".zip"===Path.extname(i).toLowerCase(),h=(h=Path.relative(n,i)).replace(/\\/g,"/"),t[h=encodeURI(h)]={size:r,md5:o},a&&(t[h].compressed=!0)))
  211. };
  212. l(Path.join(n,"src"),r.assets),l(Path.join(n,Util.manifestResDir),r.assets);
  213. let a=Path.join(o,"project.manifest"),h=Path.join(o,"version.manifest");
  214. (e=>{
  215. try{
  216. Fs.mkdirSync(e)
  217. }catch(e){
  218. if("EEXIST"!==e.code)
  219. throw e
  220. }
  221. })(o),Fs.writeFileSync(a,JSON.stringify(r)),this.log("[Build] 生成 project.manifest成功"),delete r.assets,delete r.searchPaths,Fs.writeFileSync(h,JSON.stringify(r)),this.log("[Build] 生成 version.manifest成功"),this._packageVersion()
  222. },
  223. _packageDir(e,t){
  224. let s=Fs.readdirSync(e);
  225. for(let i=0;i<s.length;i++){
  226. let r=s[i],o=Path.join(e,r),n=Fs.statSync(o);
  227. n.isFile()?t.file(r,Fs.readFileSync(o)):n.isDirectory()&&this._packageDir(o,t.folder(r))
  228. }
  229. },
  230. _packageVersion(){
  231. let{manifestResDir:e}=Util;
  232. this.log("[Pack] 开始打包版本 ...");
  233. let t=new(Editor.require("packages://hot-update-tools/node_modules/jszip")),s=Path.join(this.genManifestDir,"version.manifest");
  234. t.file("version.manifest",Fs.readFileSync(s));
  235. let i=Path.join(this.genManifestDir,"project.manifest");
  236. t.file("project.manifest",Fs.readFileSync(i));
  237. let r=Path.join(this.resourceRootDir,"src");
  238. this._packageDir(r,t.folder("src"));
  239. let o=Path.join(this.resourceRootDir,e);
  240. this._packageDir(o,t.folder(e));
  241. let n=Fs.readFileSync(s,"utf-8"),l=JSON.parse(n).version;
  242. if(this.log("[Pack] 打包版本:"+l),l!==this.version)return void this.log("[Pack] 打包版本和当前填写的版本不一致,出现异常,停止打包!");
  243. let a="ver_"+(l=l.replace(".","_"))+".zip",h=OutPut.versionsDir+'/'+this.selectDestType,d=Path.join(h,a),f=Path.join(h,"UnZip");
  244. // Fs.copySync(dd)
  245. Fs.existsSync(d)&&(Fs.unlinkSync(d),this.log("[Pack] 发现该版本的zip, 已经删除!")),t.generateNodeStream({type:"nodebuffer",streamFiles:!0}).pipe(Fs.createWriteStream(d)).on("finish",()=>{this.log("[Pack] 打包成功: "+d)}).on("error",e=>{this.log("[Pack] 打包失败:"+e.message)})
  246. // Fs.existsSync(o)?Fs.existsSync(a)?(FsExtra.emptyDirSync(e),FsExtra.copySync(s,Path.join(e,"src")),FsExtra.copySync(l,Path.join(e,t)),FsExtra.copyFileSync(o,Path.join(e,"project.manifest")),FsExtra.copyFileSync(a,Path.join(e,"version.manifest")),this.log(`已经将热更包copy到: ${e}`),this._updateServerVersion()):this.log(a+"不存在, 请点击生成热更包"):this.log(o+"不存在, 请点击生成热更包")
  247. // this._copyFiles(f);
  248. },
  249. _copyFiles(f) {
  250. let{manifestResDir:t}=Util,{resourceRootDir:r}=this,{manifestDir:i}=OutPut;
  251. let s=Path.join(r,"src"),l=Path.join(r,t);
  252. if(!Fs.existsSync(r))return void
  253. this.log("资源目录不存在: "+r+", 请先构建项目");
  254. if(!Fs.existsSync(s))return void
  255. this.log(r+"不存在src目录, 无法拷贝文件");
  256. if(!Fs.existsSync(l))return void
  257. this.log(r+"不存在res目录, 无法拷贝文件");
  258. let o=Path.join(i,"project.manifest"),a=Path.join(i,"version.manifest");
  259. if(Fs.existsSync(o)){
  260. if(Fs.existsSync(a)){
  261. Fs.emptyDirSync(f);
  262. Fs.copySync(s,Path.join(f,"src"))
  263. Fs.copySync(l,Path.join(f,t))
  264. Fs.copyFileSync(o,Path.join(f,"project.manifest"))
  265. Fs.copyFileSync(a,Path.join(f,"version.manifest"))
  266. this.log(`已经将热更包copy到: ${f}`)
  267. // this._updateServerVersion()
  268. }else{
  269. this.log(a+"不存在, 请点击生成热更包")
  270. }
  271. }else{
  272. this.log(o+"不存在, 请点击生成热更包")
  273. }
  274. },
  275. _checkResourceRootDir(e){
  276. if(Fs.existsSync(e)){
  277. let t=Path.join(e,"src");
  278. if(!Fs.existsSync(t))return
  279. this.log(`没有发现 ${t}, 请先构建项目.`),!1;
  280. let s=["res","assets"];
  281. for(let t=0;t<s.length;t++){
  282. let i=s[t];
  283. if(Fs.existsSync(Path.join(e,i))){
  284. Util.manifestResDir=i;
  285. break
  286. }
  287. }
  288. return Util.manifestResDir?(this.resourceRootDir=e,this._saveConfig(),!0):(this.log(`没有发现资源目录${s.toString()}, 请先构建项目.`),!1)
  289. }return this.log(`没有发现 ${e}, 请先构建项目.`),!1
  290. },
  291. onDoEncrypt(e,t,s,ii) {
  292. if (this.hasBuildProj) {
  293. this.log("请不要重复点击");
  294. this._genVersion(e,t,s,ii);
  295. return;
  296. }
  297. this.log("encrypt tool init");
  298. this.logView = "";
  299. this.hasEncrypt = 0;
  300. this.totalPng = [];
  301. this.hasBuildProj = true;
  302. let target = this.getBuildTips();
  303. if (Fs.existsSync(this.rootPath + "/build/"+target)) {
  304. let imgh = this.rootPath + "/build/jsb-default/frameworks/cocos2d-x/cocos/platform/CCImage.h";
  305. let imgcpp = this.rootPath + "/build/jsb-default/frameworks/cocos2d-x/cocos/platform/CCImage.cpp";
  306. if (this.buildTypeSelect == 0) {
  307. let simulatorP = Editor.url('unpack://simulator', 'utf8');
  308. let Cpath = Path.resolve(simulatorP, '..');
  309. imgh = Cpath + "/cocos/platform/CCImage.h";
  310. imgcpp = Cpath + "/cocos/platform/CCImage.cpp";
  311. this.log("img.h:" + imgh);
  312. this.log("img.cpp:" + imgcpp);
  313. };
  314. let buf = Fs.readFileSync(imgh, "UTF-8");
  315. let tmp = buf.split("//civi encrypt,don't delete//");
  316. if (tmp.length < 2) {
  317. this.log("CCImage尚未添加代码,准备添加代码");
  318. let finalRes = this.addEncryptScriptHeader(buf);
  319. Fs.writeFileSync(imgh, finalRes);
  320. let cppbuf = Fs.readFileSync(imgcpp, "UTF-8");
  321. let finalSres = this.addEncryptScript(cppbuf);
  322. Fs.writeFileSync(imgcpp, finalSres);
  323. this.log("CCImage添加代码完成");
  324. } else {
  325. this.log("CCImage已经添加代码");
  326. this.log("更新签名及密码");
  327. let cppbuf = Fs.readFileSync(imgcpp, "UTF-8");
  328. let changeBuf = this.changeEncryptSignPass(cppbuf);
  329. Fs.writeFileSync(imgcpp, changeBuf);
  330. }
  331. } else {
  332. this.log("项目还未构建,请先构建"+target+"项目");
  333. this.hasBuildProj = false
  334. return;
  335. }
  336. this.saveCfg();
  337. this.log("开始加密...请耐心等待");
  338. if (this.isNewVersion) {
  339. this.walk(this.rootPath + "/build/"+target+"/assets");
  340. }else{
  341. this.walk(this.rootPath + "/library");
  342. }
  343. this.log("共检测到" + this.totalPng.length + "张需要加密的png");
  344. for (var i = 0; i < this.totalPng.length; i++) {
  345. let pathStr = this.totalPng[i];
  346. this.beginEncrypt(pathStr, ()=>{
  347. this._genVersion(e,t,s,ii);
  348. });
  349. }
  350. if(this.totalPng.length <= 0) {
  351. this.hasBuildProj = false;
  352. this._genVersion(e,t,s,ii);
  353. }
  354. },
  355. changeEncryptSignPass(buf) {
  356. let splitStr2 = "//civi encrypt signPass,don't delete//";
  357. let tmp2 = buf.split(splitStr2);
  358. if (tmp2.length == 3) {
  359. buf = tmp2[0] + splitStr2 + "\n\
  360. ,_signKey(\"" + this.signKey + "\")\n\
  361. ,_passWord(\"" + this.passWord + "\")\n\
  362. //civi encrypt signPass,don't delete//" + tmp2[2];
  363. }
  364. return buf;
  365. },
  366. getBuildTips(){
  367. // if(this.buildTypeSelect== 1)
  368. // {
  369. // return "jsb-default";
  370. // }
  371. return "jsb-link";
  372. },
  373. versionCompareHandle(versionA, versionB) {
  374. var vA = versionA.split('.');
  375. var vB = versionB.split('.');
  376. for (var i = 0; i < vA.length; ++i) {
  377. var a = parseInt(vA[i]);
  378. var b = parseInt(vB[i] || 0);
  379. if (a === b) {
  380. continue;
  381. }
  382. else {
  383. return a - b;
  384. }
  385. }
  386. if (vB.length > vA.length) {
  387. return -1;
  388. }
  389. else {
  390. return 0;
  391. }
  392. },
  393. initPluginCfg() {
  394. let e = Editor.libraryPath;
  395. this.rootPath = e.substring(0, e.length - 7);
  396. this.cfgPath = this.rootPath + "/packages/encrypt-tool/cfg.json";
  397. this.log("项目路径为" + e.substring(0, e.length - 7));
  398. this.readCfg();
  399. this.checkBuildDir();
  400. this._updateShowEncryptInfo();
  401. },
  402. checkBuildDir(){
  403. let target = this.getBuildTips()
  404. this.log("当前加密目标模板为"+target+",即"+target+"目录下的png将被加密");
  405. if (Fs.existsSync(this.rootPath + "/build/"+target)) {
  406. let projCfg = this.rootPath + "/build/"+target+"/.cocos-project.json";
  407. let buf = Fs.readFileSync(projCfg,"UTF-8");
  408. let cfg = JSON.parse(buf);
  409. this.engineVersion = cfg.engine_version;
  410. this.log("当前引擎版本为" + this.engineVersion);
  411. let ret = this.versionCompareHandle(this.engineVersion,"2.4.0");
  412. if (ret >= 0) {
  413. this.isNewVersion = true;
  414. };
  415. }else{
  416. this.log("项目还未构建,请先构建"+target+"项目");
  417. }
  418. },
  419. saveCfg() {
  420. let newData = this.signKey + "civiEncrypt" + this.passWord + "civiEncrypt"+this.buildTypeSelect;
  421. Fs.writeFile(this.cfgPath, newData,function(error) {
  422. });
  423. },
  424. readCfg() {
  425. if (Fs.existsSync(this.cfgPath)) {
  426. let st = Fs.readFileSync(this.cfgPath, "UTF-8");
  427. let signData = st.split("civiEncrypt");
  428. if (signData.length > 1) {
  429. this.signKey = signData[0];
  430. this.passWord = signData[1];
  431. if (signData.length > 2) {
  432. this.buildTypeSelect = signData[2];
  433. };
  434. this.log("上次签名为" + this.signKey);
  435. this.log("上次密码为" + this.passWord);
  436. };
  437. } else {
  438. this.log("未检测到历史配置");
  439. }
  440. },
  441. stringToHex(str) {
  442. if (str === "")    
  443. return "";  
  444. var hexCharCode = [];  
  445. for (var i = 0; i < str.length; i++) {
  446. hexCharCode.push((str.charCodeAt(i)));  
  447. }  
  448. return hexCharCode;
  449. },
  450. checkPngSig(fileBuffer) {
  451. let isEqual = false
  452. // 判断标识头前缀
  453. if (pngBufferHeader.bufBegin) {
  454. const buf = Buffer.from(pngBufferHeader.bufBegin);
  455. isEqual = buf.equals(fileBuffer.slice(0, pngBufferHeader.bufBegin.length));
  456. }
  457. // 判断标识头后缀
  458. if (isEqual && pngBufferHeader.bufEnd) {
  459. const buf = Buffer.from(pngBufferHeader.bufEnd);
  460. isEqual = buf.equals(fileBuffer.slice(-pngBufferHeader.bufEnd.length));
  461. }
  462. if (isEqual) {
  463. return pngBufferHeader.suffix;
  464. }
  465. return ''
  466. },
  467. walk(path) {
  468. var isPNG = function(pathStr) {
  469. let extname = Path.extname(pathStr);
  470. if (extname == ".png" || extname == ".PNG") {
  471. let buf = Fs.readFileSync(pathStr);
  472. let sig = this.checkPngSig(buf);
  473. if (sig == ".png") {
  474. return true;
  475. };
  476. } else {
  477. return false;
  478. }
  479. }.bind(this);
  480. //先取出文件夹
  481. var dirList = Fs.readdirSync(path);
  482. //遍历文件夹
  483. dirList.forEach(function(item) {
  484. //判断是不是文件夹
  485. if (Fs.statSync(path + '/' + item).isDirectory()) {
  486. if (this.isNewVersion) {
  487. if (item == "internal" ) {
  488. //默认的不管pass
  489. }else{
  490. this.walk(path + '/' + item);
  491. }
  492. }else{
  493. this.walk(path + '/' + item);
  494. }
  495. } else {
  496. //判断是不是PNG图片
  497. if (isPNG(path + '/' + item)) {
  498. //进行加密
  499. this.totalPng.push(path + '/' + item);
  500. } else {
  501. // pass
  502. }
  503. }
  504. }.bind(this));
  505. },
  506. beginEncrypt(pathStr, callback) {
  507. let buf = Fs.readFileSync(pathStr);
  508. let newData = this.encryptPng(buf);
  509. Fs.writeFile(pathStr, newData,function(error) {
  510. // this.log(pathStr + "加密完成");
  511. this.hasEncrypt = this.hasEncrypt + 1;
  512. if (this.hasEncrypt == this.totalPng.length) {
  513. this.log("全部加密完成");
  514. this.log("png资源加密完成");
  515. this.hasBuildProj = false;
  516. if(callback) {
  517. callback();
  518. }
  519. };
  520. }.bind(this));
  521. },
  522. encryptPng(fileBuffer) {
  523. //预处理,先切头,再去尾
  524. let cutHeader = fileBuffer.slice(pngBufferHeader.bufBegin.length);
  525. let iendData = cutHeader.slice( - pngBufferHeader.bufEnd.length);
  526. let lastData;
  527. const buf = Buffer.from(pngBufferHeader.bufEnd);
  528. if (buf.equals(iendData)) {
  529. lastData = cutHeader.slice(0, -pngBufferHeader.bufEnd.length);
  530. } else {
  531. lastData = cutHeader;
  532. }
  533. let k = this.stringToHex(this.passWord);
  534. let klen = k.length;
  535. let kindex = 0;
  536. for (var i = 0; i < lastData.length; i++) {
  537. if (kindex >= klen) {
  538. kindex = 0;
  539. };
  540. lastData[i] = lastData[i] ^ k[kindex];
  541. kindex = kindex + 1;
  542. };
  543. let sign = new Buffer(this.signKey);
  544. let finalData = Buffer.concat([sign, lastData]);
  545. return finalData;
  546. },
  547. }
  548. });