├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── cosos │ └── CocosProjectConfig.ts ├── index.ts ├── loaderplugin.js ├── tasks │ ├── ImageEncryptTask.ts │ ├── InjectPluginTask.ts │ ├── TaskConfig.ts │ ├── TaskInterface.ts │ └── TextEncryptTask.ts └── utils │ └── RandomUtil.ts ├── static └── PAY.png └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 150, 3 | "tabWidth": 4 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 0.3.1 4 | 5 | * Cocos Creator 2.3.3 6 | * 原生平台 7 | * 修复加载远程图片时,可能不正确的问题 8 | * 修复windows上注入插件到main.js时可能不正确的问题 9 | 10 | ## 0.3.0 11 | 12 | * Cocos Creator 2.3.3 13 | * 原生平台 14 | * 支持将构建后的 txt、json 加密(带有随机性) 15 | * 支持将构建后的 png、jpg、jpeg、gif、webp 加密(带有随机性) 16 | 17 | ## 0.2.0 18 | 19 | * Cocos Creator 2.3.3 20 | * 原生平台 21 | * 支持将构建后的 jpg、jpeg 转 base64 文本(并在运行时解析为图片) 22 | 23 | ## 0.1.0 24 | 25 | * Cocos Creator 2.3.3 26 | * 原生平台 27 | * 支持将构建后的 png 转 base64 文本(并在运行时解析为图片) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Zhitao Cai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CocosCreator-Build-Encrypt 2 | 3 | [![](https://img.shields.io/badge/Release-0.3.1-orange.svg)](CHANGELOG.md) 4 | [![](https://img.shields.io/badge/Support-Cocos%20Creator%202.3.3-brightgreen.svg)](http://www.cocos.com/creator) 5 | [![](https://img.shields.io/badge/Support-Cocos%20Creator%202.3.4-brightgreen.svg)](http://www.cocos.com/creator) 6 | [![](https://img.shields.io/badge/Unknown%20Support-Cocos%20Creator%202.x.x-lightgrey.svg)](http://www.cocos.com/creator) 7 | [![](https://img.shields.io/badge/Not%20Support-Cocos%20Creator%202.4.+-red.svg)](http://www.cocos.com/creator) 8 | [![](https://img.shields.io/badge/Not%20Support-Cocos%20Creator%201.x.x-red.svg)](http://www.cocos.com/creator) 9 | 10 | 11 | 一种 Cocos Creator **「无侵入」** **「全资源支持」** **「跨平台」** **「资源处理流」** 方案。 12 | 13 | > * **「无侵入」**:使用此方案,开发者只需要针对 Cocos Creator **构建后的输出目录** 进行执行指定命令,即完成资源加密。 **实际游戏项目不需要加入/删除/修改代码等其他操作,全程无侵入**。 14 | > * **「全资源支持」**:此方案可以对 Cocos Creator 引擎本身所支持的 **所有资源文件(如:.txt,.json, .png, .mp3, .fnt等等)进行加密** ,并且依旧「无侵入」。 15 | > * **「跨平台」**:此方案可以针对不同版本的 Cocos Creator 进行单独适配,并且可以对每个 Cocos Creator 支持发布的所有平台进行单独适配。 16 | > * **「资源处理流」**:使用此方案,你可以对资源进行包括但不限于 **加密** 、 **压缩** 等处理流。 17 | 18 | ## 一、使用方式 19 | 20 | 1. 下载并初始化项目 21 | 22 | ```` 23 | git clone git@github.com:zhitaocai/CocosCreator-Build-Encrypt.git 24 | cd CocosCreator-Build-Encrypt 25 | npm install -s 26 | ```` 27 | 28 | 2. 对 **构建后的CocosCreator输出目录** 进行加密处理的命令 29 | 30 | ``` 31 | cd CocosCreator-Build-Encrypt 32 | npm run build buildOutputDirAbsPath 33 | ``` 34 | 35 | 参数说明: 36 | 37 | * `buildOutputDirAbsPath` : Cocos Creator 构建项目后的输出路径绝对路径。如:/Users/xxx/CocosCreator/HelloWorld/build/jsb-link 38 | 39 | 40 | 示例: 41 | 42 | ``` 43 | # 对 /Users/xxx/CocosCreator/HelloWorld/build/jsb-link 目录进行资源加密 44 | npm run build /Users/xxx/CocosCreator/HelloWorld/build/jsb-link 45 | ``` 46 | 47 | 3. 命令构建成功即表示已加密完成,此时可以直接用对应平台的打开方式(如:Android Studio,XCode 等)去执行此项目 48 | 49 | ## 二、Cocos Creator 支持情况 50 | 51 | ### Cocos Creator 2.4.+ 52 | 53 | 目前不支持(后续可能会有计划支持) 54 | 55 | ### Cocos Creator 2.3.3 & 2.3.4 56 | 57 | | 支持的资源 | 原生平台 | 58 | | ---------- | -------- | 59 | | png | Y | 60 | | jpg | Y | 61 | | jpeg | Y | 62 | | gif | Y | 63 | | webp | Y | 64 | | txt | Y | 65 | | json | Y | 66 | 67 | 68 | ### Cocos Creator 2.x.x( < 2.3.3) 69 | 70 | 可能可以,未进行测试,且后续也不会有计划支持 71 | 72 | ### Cocos Creator 1.x.x 73 | 74 | 后续不会有计划支持 75 | 76 | ## 三、项目实现原理 77 | 78 | > https://www.jianshu.com/p/05e8ecd89122 79 | 80 | ## 四、支持一下作者吧 81 | 82 | 如果此项目对你有帮助,不妨支持一下我吧~ 83 | 84 | ps:支持扫码催更哦🤣🤣🤣👇👇👇👇 85 | 86 | ![](static/PAY.png) 87 | 88 | 89 | ## LICENSE 90 | 91 | MIT License 92 | 93 | Copyright (c) 2020 Zhitao Cai 94 | 95 | Permission is hereby granted, free of charge, to any person obtaining a copy 96 | of this software and associated documentation files (the "Software"), to deal 97 | in the Software without restriction, including without limitation the rights 98 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 99 | copies of the Software, and to permit persons to whom the Software is 100 | furnished to do so, subject to the following conditions: 101 | 102 | The above copyright notice and this permission notice shall be included in all 103 | copies or substantial portions of the Software. 104 | 105 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 106 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 107 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 108 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 109 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 110 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 111 | SOFTWARE. 112 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cocoscreator-build-encrypt", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "14.0.18", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.18.tgz", 10 | "integrity": "sha512-0Z3nS5acM0cIV4JPzrj9g/GH0Et5vmADWtip3YOXOp1NpOLU8V3KoZDc8ny9c1pe/YSYYzQkAWob6dyV/EWg4g==" 11 | }, 12 | "arg": { 13 | "version": "4.1.3", 14 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 15 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 16 | }, 17 | "buffer-from": { 18 | "version": "1.1.1", 19 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 20 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 21 | }, 22 | "diff": { 23 | "version": "4.0.2", 24 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 25 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" 26 | }, 27 | "js-base64": { 28 | "version": "3.4.4", 29 | "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.4.4.tgz", 30 | "integrity": "sha512-IydumBqLQUWT5fwcHjVRNiHqEc3xZd44+4qZByAA1FnifCQLQyHnVrnF4F+xAroJHpkRmH2aP4TW6/Qudu34tQ==" 31 | }, 32 | "make-error": { 33 | "version": "1.3.6", 34 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 35 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 36 | }, 37 | "source-map": { 38 | "version": "0.6.1", 39 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 40 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 41 | }, 42 | "source-map-support": { 43 | "version": "0.5.19", 44 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 45 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 46 | "requires": { 47 | "buffer-from": "^1.0.0", 48 | "source-map": "^0.6.0" 49 | } 50 | }, 51 | "ts-node": { 52 | "version": "8.10.2", 53 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", 54 | "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", 55 | "requires": { 56 | "arg": "^4.1.0", 57 | "diff": "^4.0.1", 58 | "make-error": "^1.1.1", 59 | "source-map-support": "^0.5.17", 60 | "yn": "3.1.1" 61 | } 62 | }, 63 | "typescript": { 64 | "version": "3.9.6", 65 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", 66 | "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==" 67 | }, 68 | "yn": { 69 | "version": "3.1.1", 70 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 71 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cocoscreator-build-encrypt", 3 | "version": "0.1.0", 4 | "description": "将 Cocos Creator 构建后目录的部分资源进行加密", 5 | "main": "index.ts", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "ts-node ./src/index.ts" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/zhitaocai/CocosCreator-Build-Encrypt.git" 13 | }, 14 | "keywords": [ 15 | "Cocos", 16 | "CocosCreator", 17 | "Build", 18 | "Encrypt" 19 | ], 20 | "author": "zhitaocai", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/zhitaocai/CocosCreator-Build-Encrypt/issues" 24 | }, 25 | "homepage": "https://github.com/zhitaocai/CocosCreator-Build-Encrypt", 26 | "dependencies": { 27 | "@types/node": "^14.0.18", 28 | "js-base64": "^3.4.4", 29 | "ts-node": "^8.10.2", 30 | "typescript": "^3.9.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/cosos/CocosProjectConfig.ts: -------------------------------------------------------------------------------- 1 | export class CocosProjectConfig { 2 | /** 3 | * 引擎版本号 4 | * 5 | * e.g. "2.3.3" 6 | */ 7 | engineVersion: string | undefined; 8 | 9 | /** 10 | * 项目名字 11 | * 12 | * e.g. "Hello World" 13 | */ 14 | projectName: string | undefined; 15 | 16 | fromJson(json: any): CocosProjectConfig { 17 | this.engineVersion = this._getJson(json, "engineVersion"); 18 | this.projectName = this._getJson(json, "projectName"); 19 | return this; 20 | } 21 | 22 | private _getJson(json: any, key: string) { 23 | if (json) { 24 | let value = json[key]; 25 | if (value != null && value != undefined) { 26 | return value; 27 | } 28 | } 29 | return undefined; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { ImageEncryptTask } from "./tasks/ImageEncryptTask"; 2 | import { TaskConfig } from "./tasks/TaskConfig"; 3 | import { InjectPluginTask } from "./tasks/InjectPluginTask"; 4 | import { TextEncryptTask } from "./tasks/TextEncryptTask"; 5 | 6 | export class CocosBuildEncrypt { 7 | start() { 8 | let taskConfig = new TaskConfig(); 9 | let tasks = [ 10 | // 对输出的图片加密 11 | new ImageEncryptTask(), 12 | 13 | // 对出输出文本加密 14 | new TextEncryptTask(), 15 | 16 | // 注入解密插件脚本 17 | new InjectPluginTask(), 18 | ]; 19 | tasks.forEach((task) => { 20 | task.handle(taskConfig); 21 | }); 22 | console.log("恭喜,处理成功!"); 23 | } 24 | } 25 | 26 | new CocosBuildEncrypt().start(); 27 | -------------------------------------------------------------------------------- /src/loaderplugin.js: -------------------------------------------------------------------------------- 1 | // 2 | // THIS FILE IS AUTOMATICALLY GENERATED! DO NOT EDIT BY HAND! 3 | // 4 | (function (global, factory) { 5 | typeof exports === "object" && typeof module !== "undefined" 6 | ? (module.exports = factory()) 7 | : typeof define === "function" && define.amd 8 | ? define(factory) 9 | : // cf. https://github.com/dankogai/js-base64/issues/119 10 | (function () { 11 | // existing version for noConflict() 12 | const _Base64 = global.Base64; 13 | const gBase64 = factory(); 14 | gBase64.noConflict = () => { 15 | global.Base64 = _Base64; 16 | return gBase64; 17 | }; 18 | if (global.Meteor) { 19 | // Meteor.js 20 | Base64 = gBase64; 21 | } 22 | global.Base64 = gBase64; 23 | })(); 24 | })(typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : this, function () { 25 | "use strict"; 26 | 27 | /** 28 | * base64.ts 29 | * 30 | * Licensed under the BSD 3-Clause License. 31 | * http://opensource.org/licenses/BSD-3-Clause 32 | * 33 | * References: 34 | * http://en.wikipedia.org/wiki/Base64 35 | * 36 | * @author Dan Kogai (https://github.com/dankogai) 37 | */ 38 | const version = "3.4.4"; 39 | /** 40 | * @deprecated use lowercase `version`. 41 | */ 42 | const VERSION = version; 43 | const _hasatob = typeof atob === "function"; 44 | const _hasbtoa = typeof btoa === "function"; 45 | const _hasBuffer = typeof Buffer === "function"; 46 | const b64ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 47 | const b64chs = [...b64ch]; 48 | const b64tab = ((a) => { 49 | let tab = {}; 50 | a.forEach((c, i) => (tab[c] = i)); 51 | return tab; 52 | })(b64chs); 53 | const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; 54 | const _fromCC = String.fromCharCode.bind(String); 55 | const _U8Afrom = 56 | typeof Uint8Array.from === "function" 57 | ? Uint8Array.from.bind(Uint8Array) 58 | : (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn)); 59 | const _mkUriSafe = (src) => src.replace(/[+\/]/g, (m0) => (m0 == "+" ? "-" : "_")).replace(/=+$/m, ""); 60 | const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, ""); 61 | /** 62 | * polyfill version of `btoa` 63 | */ 64 | const btoaPolyfill = (bin) => { 65 | // console.log('polyfilled'); 66 | let u32, 67 | c0, 68 | c1, 69 | c2, 70 | asc = ""; 71 | const pad = bin.length % 3; 72 | for (let i = 0; i < bin.length; ) { 73 | if ((c0 = bin.charCodeAt(i++)) > 255 || (c1 = bin.charCodeAt(i++)) > 255 || (c2 = bin.charCodeAt(i++)) > 255) 74 | throw new TypeError("invalid character found"); 75 | u32 = (c0 << 16) | (c1 << 8) | c2; 76 | asc += b64chs[(u32 >> 18) & 63] + b64chs[(u32 >> 12) & 63] + b64chs[(u32 >> 6) & 63] + b64chs[u32 & 63]; 77 | } 78 | return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; 79 | }; 80 | /** 81 | * does what `window.btoa` of web browsers do. 82 | * @param {String} bin binary string 83 | * @returns {string} Base64-encoded string 84 | */ 85 | const _btoa = _hasbtoa ? (bin) => btoa(bin) : _hasBuffer ? (bin) => Buffer.from(bin, "binary").toString("base64") : btoaPolyfill; 86 | const _fromUint8Array = _hasBuffer 87 | ? (u8a) => Buffer.from(u8a).toString("base64") 88 | : (u8a) => { 89 | // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326 90 | const maxargs = 0x1000; 91 | let strs = []; 92 | for (let i = 0, l = u8a.length; i < l; i += maxargs) { 93 | strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); 94 | } 95 | return btoa(strs.join("")); 96 | }; 97 | /** 98 | * converts a Uint8Array to a Base64 string. 99 | * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 100 | * @returns {string} Base64 string 101 | */ 102 | const fromUint8Array = (u8a, urlsafe = false) => (urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a)); 103 | /** 104 | * @deprecated should have been internal use only. 105 | * @param {string} src UTF-8 string 106 | * @returns {string} UTF-16 string 107 | */ 108 | const utob = (src) => unescape(encodeURIComponent(src)); 109 | // 110 | const _encode = _hasBuffer ? (s) => Buffer.from(s, "utf8").toString("base64") : (s) => _btoa(utob(s)); 111 | /** 112 | * converts a UTF-8-encoded string to a Base64 string. 113 | * @param {boolean} [urlsafe] if `true` make the result URL-safe 114 | * @returns {string} Base64 string 115 | */ 116 | const encode = (src, urlsafe = false) => (urlsafe ? _mkUriSafe(_encode(src)) : _encode(src)); 117 | /** 118 | * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. 119 | * @returns {string} Base64 string 120 | */ 121 | const encodeURI = (src) => encode(src, true); 122 | /** 123 | * @deprecated should have been internal use only. 124 | * @param {string} src UTF-16 string 125 | * @returns {string} UTF-8 string 126 | */ 127 | const btou = (src) => decodeURIComponent(escape(src)); 128 | /** 129 | * polyfill version of `atob` 130 | */ 131 | const atobPolyfill = (asc) => { 132 | // console.log('polyfilled'); 133 | asc = asc.replace(/\s+/g, ""); 134 | if (!b64re.test(asc)) throw new TypeError("malformed base64."); 135 | asc += "==".slice(2 - (asc.length & 3)); 136 | let u24, 137 | bin = "", 138 | r1, 139 | r2; 140 | for (let i = 0; i < asc.length; ) { 141 | u24 = 142 | (b64tab[asc.charAt(i++)] << 18) | 143 | (b64tab[asc.charAt(i++)] << 12) | 144 | ((r1 = b64tab[asc.charAt(i++)]) << 6) | 145 | (r2 = b64tab[asc.charAt(i++)]); 146 | bin += 147 | r1 === 64 148 | ? _fromCC((u24 >> 16) & 255) 149 | : r2 === 64 150 | ? _fromCC((u24 >> 16) & 255, (u24 >> 8) & 255) 151 | : _fromCC((u24 >> 16) & 255, (u24 >> 8) & 255, u24 & 255); 152 | } 153 | return bin; 154 | }; 155 | /** 156 | * does what `window.atob` of web browsers do. 157 | * @param {String} asc Base64-encoded string 158 | * @returns {string} binary string 159 | */ 160 | const _atob = _hasatob ? (asc) => atob(_tidyB64(asc)) : _hasBuffer ? (asc) => Buffer.from(asc, "base64").toString("binary") : atobPolyfill; 161 | const _decode = _hasBuffer ? (a) => Buffer.from(a, "base64").toString("utf8") : (a) => btou(_atob(a)); 162 | const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => (m0 == "-" ? "+" : "/"))); 163 | /** 164 | * converts a Base64 string to a UTF-8 string. 165 | * @param {String} src Base64 string. Both normal and URL-safe are supported 166 | * @returns {string} UTF-8 string 167 | */ 168 | const decode = (src) => _decode(_unURI(src)); 169 | /** 170 | * converts a Base64 string to a Uint8Array. 171 | */ 172 | const toUint8Array = _hasBuffer ? (a) => _U8Afrom(Buffer.from(_unURI(a), "base64")) : (a) => _U8Afrom(_atob(_unURI(a)), (c) => c.charCodeAt(0)); 173 | const _noEnum = (v) => { 174 | return { 175 | value: v, 176 | enumerable: false, 177 | writable: true, 178 | configurable: true, 179 | }; 180 | }; 181 | /** 182 | * extend String.prototype with relevant methods 183 | */ 184 | const extendString = function () { 185 | const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body)); 186 | _add("fromBase64", function () { 187 | return decode(this); 188 | }); 189 | _add("toBase64", function (urlsafe) { 190 | return encode(this, urlsafe); 191 | }); 192 | _add("toBase64URI", function () { 193 | return encode(this, true); 194 | }); 195 | _add("toBase64URL", function () { 196 | return encode(this, true); 197 | }); 198 | _add("toUint8Array", function () { 199 | return toUint8Array(this); 200 | }); 201 | }; 202 | /** 203 | * extend Uint8Array.prototype with relevant methods 204 | */ 205 | const extendUint8Array = function () { 206 | const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body)); 207 | _add("toBase64", function (urlsafe) { 208 | return fromUint8Array(this, urlsafe); 209 | }); 210 | _add("toBase64URI", function () { 211 | return fromUint8Array(this, true); 212 | }); 213 | _add("toBase64URL", function () { 214 | return fromUint8Array(this, true); 215 | }); 216 | }; 217 | /** 218 | * extend Builtin prototypes with relevant methods 219 | */ 220 | const extendBuiltins = () => { 221 | extendString(); 222 | extendUint8Array(); 223 | }; 224 | const gBase64 = { 225 | version: version, 226 | VERSION: VERSION, 227 | atob: _atob, 228 | atobPolyfill: atobPolyfill, 229 | btoa: _btoa, 230 | btoaPolyfill: btoaPolyfill, 231 | fromBase64: decode, 232 | toBase64: encode, 233 | encode: encode, 234 | encodeURI: encodeURI, 235 | encodeURL: encodeURI, 236 | utob: utob, 237 | btou: btou, 238 | decode: decode, 239 | fromUint8Array: fromUint8Array, 240 | toUint8Array: toUint8Array, 241 | extendString: extendString, 242 | extendUint8Array: extendUint8Array, 243 | extendBuiltins: extendBuiltins, 244 | }; 245 | 246 | // 247 | // export Base64 to the namespace 248 | // 249 | // ES5 is yet to have Object.assign() that may make transpilers unhappy. 250 | // gBase64.Base64 = Object.assign({}, gBase64); 251 | gBase64.Base64 = {}; 252 | Object.keys(gBase64).forEach((k) => (gBase64.Base64[k] = gBase64[k])); 253 | return gBase64; 254 | }); 255 | 256 | if (CC_JSB) { 257 | 258 | function downloadText(item) { 259 | var url = item.url; 260 | var result = jsb.fileUtils.getStringFromFile(url); 261 | if (result) { 262 | result.substring(0, result.length - 10); 263 | } 264 | if (typeof result === "string" && result) { 265 | return result; 266 | } else { 267 | return new Error("Download text failed: " + url); 268 | } 269 | } 270 | 271 | /** 272 | * 加载图片 273 | * 274 | * @param {string} data 可以是图片地址,也开始是图片的Base64编码 275 | * @param {Function} callback 回调函数 276 | */ 277 | function loadImage(data, callback) { 278 | let img = new Image(); 279 | img.src = data; 280 | img.onload = function (info) { 281 | callback(null, img); 282 | }; 283 | 284 | img.onerror = function (event) { 285 | callback(new Error("load image fail:" + img.src), null); 286 | }; // Don't return anything to use async loading. 287 | } 288 | 289 | 290 | function downloadImage(item, callback) { 291 | if (item.url.startsWith("http")) { 292 | // 来自网络的图片,直接加载 293 | loadImage(item.url, callback); 294 | } else { 295 | // 本地图片,先读取Base64,然后将Base64给Image加载出原图 296 | let text = downloadText(item); 297 | if (text instanceof Error) { 298 | callback(text, null); 299 | } else { 300 | loadImage(text, callback); 301 | } 302 | } 303 | } 304 | 305 | function downloadSrcText(item) { 306 | var url = item.url; 307 | var result = jsb.fileUtils.getStringFromFile(url); 308 | if (result) { 309 | result = result.substring(0, result.length - 10); 310 | } 311 | if (typeof result === "string" && result) { 312 | return Base64.decode(result); 313 | } else { 314 | return new Error("Download text failed: " + url); 315 | } 316 | } 317 | 318 | cc.loader.addDownloadHandlers({ 319 | // Image 320 | png: downloadImage, 321 | jpg: downloadImage, 322 | jpeg: downloadImage, 323 | gif: downloadImage, 324 | webp: downloadImage, 325 | 326 | // Text 327 | txt: downloadSrcText, 328 | // xml: downloadSrcText, 329 | // vsh: downloadSrcText, 330 | // fsh: downloadSrcText, 331 | // atlas: downloadSrcText, 332 | // tmx: downloadSrcText, 333 | // tsx: downloadSrcText, 334 | json: downloadSrcText, 335 | // ExportJson: downloadSrcText, 336 | // plist: downloadSrcText, 337 | // fnt: downloadSrcText, 338 | // default: downloadSrcText, 339 | }); 340 | } 341 | -------------------------------------------------------------------------------- /src/tasks/ImageEncryptTask.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { RandomUtil } from "../utils/RandomUtil"; 4 | import { TaskConfig } from "./TaskConfig"; 5 | import { TaskInterface } from "./TaskInterface"; 6 | 7 | enum ImageType { 8 | PNG, 9 | JPG, 10 | JPEG, 11 | GIF, 12 | WEBP, 13 | } 14 | 15 | type ImageObject = { 16 | /** 17 | * 图片类型 18 | */ 19 | type: ImageType; 20 | 21 | /** 22 | * 图片路径 23 | */ 24 | filePath: string; 25 | }; 26 | 27 | export class ImageEncryptTask implements TaskInterface { 28 | /** 29 | * 处理任务 30 | * 31 | * @param taskConfig 配置参数 32 | */ 33 | handle(taskConfig: TaskConfig): void { 34 | // 收集输出目录图片文件 35 | let imgs: ImageObject[] = []; 36 | this._collectImageFilePaths(taskConfig.buildOutputResDirPath, imgs); 37 | console.log(`图片处理:找到 ${imgs.length} 张原始图片`); 38 | 39 | // 加密图片文件 40 | this._encryptImage(imgs); 41 | console.log(`图片处理:${imgs.length} 张原始图片已加密完成`); 42 | } 43 | 44 | /** 45 | * 获取指定目录的所有图片文件路径 46 | * 47 | * @param dirName 目录名 48 | * @param imgs 接受图片文件的数组 49 | */ 50 | private _collectImageFilePaths(dirName: string, imgs: ImageObject[]) { 51 | if (!fs.existsSync(dirName)) { 52 | throw new Error(`${dirName} 目录不存在`); 53 | } 54 | 55 | let files = fs.readdirSync(dirName); 56 | files.forEach((fileName: fs.PathLike) => { 57 | let filePath = path.join(dirName, fileName.toString()); 58 | let stat: fs.Stats = fs.statSync(filePath); 59 | if (stat.isDirectory()) { 60 | this._collectImageFilePaths(filePath, imgs); 61 | } else { 62 | let fileExtName = path.extname(filePath); 63 | switch (fileExtName) { 64 | case ".png": 65 | imgs.push({ 66 | type: ImageType.PNG, 67 | filePath: filePath, 68 | }); 69 | break; 70 | case ".jpg": 71 | imgs.push({ 72 | type: ImageType.JPG, 73 | filePath: filePath, 74 | }); 75 | break; 76 | case ".jpeg": 77 | imgs.push({ 78 | type: ImageType.JPEG, 79 | filePath: filePath, 80 | }); 81 | case ".gif": 82 | imgs.push({ 83 | type: ImageType.GIF, 84 | filePath: filePath, 85 | }); 86 | case ".webp": 87 | imgs.push({ 88 | type: ImageType.WEBP, 89 | filePath: filePath, 90 | }); 91 | break; 92 | } 93 | } 94 | }); 95 | } 96 | 97 | /** 98 | * 加密图片 99 | */ 100 | private _encryptImage(imgs: ImageObject[]) { 101 | imgs.forEach((imgObj: ImageObject) => { 102 | let imgBuffer: Buffer = fs.readFileSync(imgObj.filePath); 103 | if (imgBuffer.toString().startsWith("data")) { 104 | return; 105 | } 106 | let imgBase64String: string = ""; 107 | switch (imgObj.type) { 108 | case ImageType.PNG: 109 | imgBase64String += "data:image/png;base64,"; 110 | break; 111 | case ImageType.JPG: 112 | imgBase64String += "data:image/jpg;base64,"; 113 | break; 114 | case ImageType.JPEG: 115 | imgBase64String += "data:image/jpeg;base64,"; 116 | break; 117 | case ImageType.GIF: 118 | imgBase64String += "data:image/gif;base64,"; 119 | break; 120 | case ImageType.WEBP: 121 | imgBase64String += "data:image/webp;base64,"; 122 | break; 123 | } 124 | imgBase64String += imgBuffer.toString("base64"); 125 | // 最后加上10位随机数 126 | imgBase64String += RandomUtil.randomString(10); 127 | fs.writeFileSync(imgObj.filePath, imgBase64String); 128 | }); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/tasks/InjectPluginTask.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { TaskConfig } from "./TaskConfig"; 4 | import { TaskInterface } from "./TaskInterface"; 5 | 6 | /** 7 | * 注入解密插件脚本任务 8 | */ 9 | export class InjectPluginTask implements TaskInterface { 10 | handle(taskConfig: TaskConfig): void { 11 | this._cpLoaderPlugin(taskConfig); 12 | this._addLoaderPluginToMainJs(taskConfig); 13 | } 14 | 15 | /** 16 | * 复制(解密)插件脚本到打包目录 17 | */ 18 | private _cpLoaderPlugin(taskConfig: TaskConfig) { 19 | // 创建插件目录 20 | if (fs.existsSync(taskConfig.buildOutputLoaderPluginJsFilePath)) { 21 | if (fs.statSync(taskConfig.buildOutputLoaderPluginJsFilePath).isFile()) { 22 | console.log(`插件脚本注入:删除已存在文件 ${taskConfig.buildOutputLoaderPluginJsFilePath}`); 23 | fs.unlinkSync(taskConfig.buildOutputLoaderPluginJsFilePath); 24 | } 25 | } else { 26 | fs.mkdirSync(path.dirname(taskConfig.buildOutputLoaderPluginJsFilePath)); 27 | console.log(`插件脚本注入:创建目录成功`); 28 | } 29 | 30 | // 写入文件 31 | console.log(`插件脚本注入:即将复制插件脚本到 ${taskConfig.buildOutputLoaderPluginJsFilePath}`); 32 | let inputJsFileBuffer: Buffer = fs.readFileSync(taskConfig.inputLoaderPluginJsFilePath); 33 | fs.writeFileSync(taskConfig.buildOutputLoaderPluginJsFilePath, inputJsFileBuffer.toString()); 34 | console.log(`插件脚本注入:复制插件脚本成功`); 35 | } 36 | 37 | /** 38 | * 在构建后的 main.js 加入插脚脚本的调用代码 39 | */ 40 | private _addLoaderPluginToMainJs(taskConfig: TaskConfig) { 41 | // 插件代码相对于构建src目录的相对路径 42 | // e.g. assets/loaderplugin.js 43 | let loaderpluginRelativePath = path.join( 44 | path.basename(path.dirname(taskConfig.buildOutputLoaderPluginJsFilePath)), 45 | path.basename(taskConfig.buildOutputLoaderPluginJsFilePath) 46 | ); 47 | 48 | let fileBuffer: Buffer = fs.readFileSync(taskConfig.buildOutputMainJsFilePath); 49 | let fileContentText = fileBuffer.toString(); 50 | if (fileContentText.match(loaderpluginRelativePath)) { 51 | console.log(`插件脚本注入:已注入到 main.js,将不再处理`); 52 | return; 53 | } 54 | 55 | // 注入插件到 main.js 56 | let fileChunks = fileContentText.split("var jsList = settings.jsList;"); 57 | let aopCodeBlock = ` 58 | var jsList = settings.jsList; 59 | if (jsList == null) { 60 | jsList = []; 61 | } 62 | jsList.unshift("${loaderpluginRelativePath}"); 63 | `; 64 | // let aopCodeBlock = ` 65 | // var jsList = settings.jsList; 66 | 67 | // ////////////////////////////////////////// 68 | // // 插入代码:开始 69 | 70 | // if (jsList == null) { 71 | // jsList = []; 72 | // } 73 | // jsList.unshift("${loaderpluginRelativePath}"); 74 | 75 | // // 插入代码:结束 76 | // ////////////////////////////////////////// 77 | // `; 78 | let newMainJsFileContent = fileChunks.join(aopCodeBlock); 79 | fs.writeFileSync(taskConfig.buildOutputMainJsFilePath, newMainJsFileContent); 80 | console.log(`插件脚本注入:注入 main.js 成功`); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/tasks/TaskConfig.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { CocosProjectConfig } from "../cosos/CocosProjectConfig"; 4 | 5 | export class TaskConfig { 6 | /** 7 | * 构建输出目录的平台路径 8 | * 9 | * e.g. 10 | * 11 | * /Users/xxx/CocosCreator/CocosGame/build/jsb-link 12 | */ 13 | buildOutputDirPath: string; 14 | 15 | /** 16 | * 构建输出目录的项目配置 17 | * 18 | * e.g. 19 | * 20 | * /Users/xxx/CocosCreator/CocosGame/build/jsb-link/.cocos-project.json 21 | */ 22 | buildOutputCocosProjectJsonFilePath: string; 23 | 24 | /** 25 | * 构建输出目录的资源目录 26 | * 27 | * e.g. 28 | * 29 | * /Users/xxx/CocosCreator/CocosGame/build/jsb-link/res 30 | */ 31 | buildOutputResDirPath: string; 32 | 33 | /** 34 | * 构建输出目录的 main.js 35 | * 36 | * e.g. 37 | * 38 | * /Users/xxx/CocosCreator/CocosGame/build/jsb-link/main.js 39 | */ 40 | buildOutputMainJsFilePath: string; 41 | 42 | /** 43 | * 插件脚本输出路径 44 | * 45 | * e.g. 46 | * 47 | * /Users/xxx/CocosCreator/CocosGame/build/jsb-link/src/assets/loaderplugin.js 48 | */ 49 | buildOutputLoaderPluginJsFilePath: string; 50 | 51 | /** 52 | * 插件脚本输入路径 53 | * 54 | * e.g. 55 | * 56 | * ./loaderplugin.js 57 | */ 58 | inputLoaderPluginJsFilePath: string; 59 | 60 | /** 61 | * Cocos 项目配置 62 | */ 63 | cocosProject: CocosProjectConfig | undefined; 64 | 65 | constructor() { 66 | // console.log("当前执行文件所在目录路径", __dirname); 67 | // console.log("当前执行文件绝对路径", __filename); 68 | console.log("当前执行node命令的目录路径", process.cwd()); 69 | console.log("可执行文件路径", process.argv[0]); 70 | console.log("将执行的脚本路径", process.argv[1]); 71 | console.log("传入参数", process.argv.slice(2)); 72 | 73 | this.buildOutputDirPath = path.join(process.argv[2], ""); 74 | this.buildOutputCocosProjectJsonFilePath = path.join(this.buildOutputDirPath, ".cocos-project.json"); 75 | this.buildOutputResDirPath = path.join(this.buildOutputDirPath, "res"); 76 | this.buildOutputMainJsFilePath = path.join(this.buildOutputDirPath, "main.js"); 77 | this.buildOutputLoaderPluginJsFilePath = path.join(this.buildOutputDirPath, "src/assets/loaderplugin.js"); 78 | this.inputLoaderPluginJsFilePath = path.join(path.dirname(process.argv[1]), "loaderplugin.js"); 79 | 80 | if (fs.existsSync(this.buildOutputCocosProjectJsonFilePath)) { 81 | this.cocosProject = new CocosProjectConfig().fromJson(JSON.parse(fs.readFileSync(this.buildOutputCocosProjectJsonFilePath).toString())); 82 | } 83 | 84 | console.log("初始化项目配置"); 85 | console.log(this); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/tasks/TaskInterface.ts: -------------------------------------------------------------------------------- 1 | import { TaskConfig } from "./TaskConfig"; 2 | 3 | export interface TaskInterface { 4 | /** 5 | * 处理任务 6 | * 7 | * @param taskConfig 配置参数 8 | */ 9 | handle(taskConfig: TaskConfig): void; 10 | } 11 | -------------------------------------------------------------------------------- /src/tasks/TextEncryptTask.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { TaskConfig } from "./TaskConfig"; 4 | import { TaskInterface } from "./TaskInterface"; 5 | import { RandomUtil } from "../utils/RandomUtil"; 6 | import { toBase64 } from "js-base64"; 7 | 8 | enum TextType { 9 | TXT, 10 | JSON, 11 | } 12 | 13 | type TextObject = { 14 | /** 15 | * 图片类型 16 | */ 17 | type: TextType; 18 | 19 | /** 20 | * 图片路径 21 | */ 22 | filePath: string; 23 | }; 24 | 25 | export class TextEncryptTask implements TaskInterface { 26 | handle(taskConfig: TaskConfig): void { 27 | // 收集输出目录的文本文件 28 | let texts: TextObject[] = []; 29 | this._collectTextFilePaths(taskConfig.buildOutputResDirPath, texts); 30 | console.log(`文本处理:找到 ${texts.length} 个文本文件`); 31 | 32 | // 加密文本文件 33 | this._encryptText(texts); 34 | console.log(`文本处理:${texts.length} 个文本文件已加密完成`); 35 | } 36 | 37 | /** 38 | * 获取指定目录的所有文本文件路径 39 | * 40 | * @param dirName 目录名 41 | * @param texts 接受文本文件的数组 42 | */ 43 | private _collectTextFilePaths(dirName: string, texts: TextObject[]) { 44 | if (!fs.existsSync(dirName)) { 45 | throw new Error(`${dirName} 目录不存在`); 46 | } 47 | 48 | let files = fs.readdirSync(dirName); 49 | files.forEach((fileName: fs.PathLike) => { 50 | let filePath = path.join(dirName, fileName.toString()); 51 | let stat: fs.Stats = fs.statSync(filePath); 52 | if (stat.isDirectory()) { 53 | this._collectTextFilePaths(filePath, texts); 54 | } else { 55 | let fileExtName = path.extname(filePath); 56 | switch (fileExtName) { 57 | case ".txt": 58 | texts.push({ 59 | type: TextType.TXT, 60 | filePath: filePath, 61 | }); 62 | break; 63 | case ".json": 64 | texts.push({ 65 | type: TextType.JSON, 66 | filePath: filePath, 67 | }); 68 | break; 69 | } 70 | } 71 | }); 72 | } 73 | /** 74 | * 加密文本 75 | */ 76 | private _encryptText(imgs: TextObject[]) { 77 | imgs.forEach((imgObj: TextObject) => { 78 | let buffer: Buffer = fs.readFileSync(imgObj.filePath); 79 | // 使用 node 自带的 base64 80 | // let encodeText: string = buffer.toString("base64"); 81 | 82 | // 使用 js-base64 库,这是为了方便解密的时候,使用同样的库去解密 83 | let encodeText = toBase64(buffer.toString()); 84 | encodeText += RandomUtil.randomString(10); 85 | fs.writeFileSync(imgObj.filePath, encodeText); 86 | }); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/utils/RandomUtil.ts: -------------------------------------------------------------------------------- 1 | export class RandomUtil { 2 | private static _keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 3 | static randomString(length: number): string { 4 | let str = ""; 5 | for (let i = 0; i < length; i++) { 6 | str += this._keys[Math.floor((this._keys.length - 1) * Math.random())]; 7 | } 8 | return str; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /static/PAY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhitaocai/CocosCreator-Build-Encrypt/50ac0450b3276ab8ef551f4341f47beb5523fcf7/static/PAY.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true /* Enable all strict type-checking options. */, 29 | 30 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 31 | // "strictNullChecks": true, /* Enable strict null checks. */ 32 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 33 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 34 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 35 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 36 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 37 | 38 | /* Additional Checks */ 39 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 40 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 41 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 42 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 43 | 44 | /* Module Resolution Options */ 45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 47 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 49 | // "typeRoots": [], /* List of folders to include type definitions from. */ 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | 56 | /* Source Map Options */ 57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | 62 | /* Experimental Options */ 63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 65 | 66 | /* Advanced Options */ 67 | "skipLibCheck": true /* Skip type checking of declaration files. */, 68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 69 | } 70 | } 71 | --------------------------------------------------------------------------------