cocos-obfuscator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ # 安装方法总结
2
+
3
+ ## 🚀 快速选择指南
4
+
5
+ 根据你的使用场景,选择最适合的方法:
6
+
7
+ | 场景 | 推荐方法 | 命令 |
8
+ |------|---------|------|
9
+ | **本地开发,单个项目** | npm link | `npm link` → `npm link cocos-obfuscator` |
10
+ | **本地开发,多个项目** | file: 路径 | `"cocos-obfuscator": "file:../path"` |
11
+ | **团队协作,使用 Gitee** | Git 安装 | `git+https://gitee.com/...` |
12
+ | **团队协作,使用 GitHub** | Git 安装 | `git+https://github.com/...` |
13
+ | **企业内网** | Verdaccio | 自建私有 npm 仓库 |
14
+ | **使用 GitLab** | GitLab Package | GitLab Package Registry |
15
+
16
+ ---
17
+
18
+ ## 方法对比
19
+
20
+ ### 1. npm link(最简单,适合本地)
21
+
22
+ **优点**:
23
+ - ✅ 安装简单
24
+ - ✅ 修改代码后自动生效
25
+ - ✅ 适合开发调试
26
+
27
+ **缺点**:
28
+ - ❌ 需要手动在每个项目链接
29
+ - ❌ 不适合生产环境
30
+
31
+ **使用**:
32
+ ```bash
33
+ cd cocos-obfuscator && npm link
34
+ cd your-project && npm link cocos-obfuscator
35
+ ```
36
+
37
+ ---
38
+
39
+ ### 2. file: 路径(推荐,适合团队)
40
+
41
+ **优点**:
42
+ - ✅ 版本控制友好
43
+ - ✅ 适合团队协作
44
+ - ✅ 可以指定相对路径
45
+
46
+ **缺点**:
47
+ - ❌ 路径变化需要更新
48
+ - ❌ 跨机器需要调整路径
49
+
50
+ **使用**:
51
+ ```json
52
+ {
53
+ "devDependencies": {
54
+ "cocos-obfuscator": "file:../cocos-obfuscator"
55
+ }
56
+ }
57
+ ```
58
+
59
+ ---
60
+
61
+ ### 3. Gitee Git 安装(推荐,国内访问快)
62
+
63
+ **优点**:
64
+ - ✅ 国内访问速度快
65
+ - ✅ 支持私有仓库
66
+ - ✅ 版本控制完善
67
+
68
+ **缺点**:
69
+ - ❌ Gitee 不支持 npm registry
70
+ - ❌ 安装速度较慢(需要 clone)
71
+
72
+ **使用**:
73
+ ```bash
74
+ # 公开仓库
75
+ npm install git+https://gitee.com/username/cocos-obfuscator.git
76
+
77
+ # 私有仓库(SSH)
78
+ npm install git+ssh://git@gitee.com/username/cocos-obfuscator.git
79
+ ```
80
+
81
+ **详细说明**:查看 [GITEE.md](./GITEE.md)
82
+
83
+ ---
84
+
85
+ ### 4. GitHub Git 安装
86
+
87
+ **优点**:
88
+ - ✅ 全球访问
89
+ - ✅ 支持 GitHub Packages(npm registry)
90
+ - ✅ 生态完善
91
+
92
+ **缺点**:
93
+ - ❌ 国内访问可能较慢
94
+
95
+ **使用**:
96
+ ```bash
97
+ npm install git+https://github.com/username/cocos-obfuscator.git
98
+ ```
99
+
100
+ ---
101
+
102
+ ### 5. 发布到 npm(公开)
103
+
104
+ **优点**:
105
+ - ✅ 安装简单
106
+ - ✅ 版本管理完善
107
+ - ✅ 全球可用
108
+
109
+ **缺点**:
110
+ - ❌ 包是公开的
111
+ - ❌ 需要 npm 账号
112
+
113
+ **使用**:
114
+ ```bash
115
+ npm install cocos-obfuscator
116
+ ```
117
+
118
+ ---
119
+
120
+ ### 6. 私有 npm 仓库
121
+
122
+ **方案 A:Verdaccio(自建)**
123
+
124
+ ```bash
125
+ # 安装 Verdaccio
126
+ npm install -g verdaccio
127
+
128
+ # 启动服务
129
+ verdaccio
130
+
131
+ # 配置使用
132
+ npm config set registry http://localhost:4873
133
+
134
+ # 发布
135
+ cd cocos-obfuscator && npm publish
136
+ ```
137
+
138
+ **方案 B:GitLab Package Registry**
139
+
140
+ ```json
141
+ {
142
+ "name": "@your-scope/cocos-obfuscator",
143
+ "publishConfig": {
144
+ "@your-scope:registry": "https://gitlab.com/api/v4/projects/ID/packages/npm/"
145
+ }
146
+ }
147
+ ```
148
+
149
+ **方案 C:华为云 CodeArts**
150
+
151
+ 在华为云 CodeArts 创建 npm 私有仓库,配置后发布。
152
+
153
+ ---
154
+
155
+ ## 📋 完整安装步骤示例
156
+
157
+ ### 示例 1:使用 Gitee(推荐国内用户)
158
+
159
+ #### 步骤 1:推送到 Gitee
160
+
161
+ ```bash
162
+ cd cocos-obfuscator
163
+ git init
164
+ git add .
165
+ git commit -m "Initial commit"
166
+ git remote add origin https://gitee.com/your-username/cocos-obfuscator.git
167
+ git push -u origin master
168
+ ```
169
+
170
+ #### 步骤 2:在其他项目中安装
171
+
172
+ ```json
173
+ {
174
+ "devDependencies": {
175
+ "cocos-obfuscator": "git+https://gitee.com/your-username/cocos-obfuscator.git"
176
+ },
177
+ "scripts": {
178
+ "obfuscate": "cocos-obfuscate"
179
+ }
180
+ }
181
+ ```
182
+
183
+ ```bash
184
+ npm install
185
+ npm run obfuscate
186
+ ```
187
+
188
+ ---
189
+
190
+ ### 示例 2:使用 npm link(本地开发)
191
+
192
+ ```bash
193
+ # 在 cocos-obfuscator 目录
194
+ npm link
195
+
196
+ # 在其他项目
197
+ npm link cocos-obfuscator
198
+ cocos-obfuscate
199
+ ```
200
+
201
+ ---
202
+
203
+ ### 示例 3:使用 file: 路径(团队协作)
204
+
205
+ ```json
206
+ {
207
+ "devDependencies": {
208
+ "cocos-obfuscator": "file:D:/projects/cocos-obfuscator"
209
+ }
210
+ }
211
+ ```
212
+
213
+ ```bash
214
+ npm install
215
+ npx cocos-obfuscate
216
+ ```
217
+
218
+ ---
219
+
220
+ ## 🔍 选择建议
221
+
222
+ ### 个人开发者
223
+ - **推荐**:npm link 或 file: 路径
224
+
225
+ ### 小团队(2-5人)
226
+ - **推荐**:Gitee Git 安装 或 file: 路径
227
+
228
+ ### 大团队(5人以上)
229
+ - **推荐**:私有 npm 仓库(Verdaccio)或 GitLab Package
230
+
231
+ ### 企业用户
232
+ - **推荐**:私有 npm 仓库 或 企业级制品仓库(如华为云 CodeArts)
233
+
234
+ ---
235
+
236
+ ## 📚 相关文档
237
+
238
+ - [README.md](./README.md) - 基本使用说明
239
+ - [GITEE.md](./GITEE.md) - Gitee 详细使用指南
240
+ - [INSTALL.md](./INSTALL.md) - 完整安装方法
241
+ - [QUICKSTART.md](./QUICKSTART.md) - 快速开始
242
+ - [在其他项目中使用.md](./在其他项目中使用.md) - 中文使用指南
243
+
244
+ ---
245
+
246
+ ## ❓ 常见问题
247
+
248
+ ### Q: Gitee 支持 npm 包托管吗?
249
+
250
+ A: 目前不支持,但可以从 Git 仓库直接安装。详见 [GITEE.md](./GITEE.md)
251
+
252
+ ### Q: 哪种方法最快?
253
+
254
+ A: npm link 最快,但只适合本地开发。
255
+
256
+ ### Q: 哪种方法最适合团队?
257
+
258
+ A: 从 Git 仓库安装(Gitee/GitHub)或使用私有 npm 仓库。
259
+
260
+ ### Q: 如何更新包?
261
+
262
+ A:
263
+ - npm link: 修改代码后自动生效
264
+ - file: 路径: `npm install`
265
+ - Git 安装: `npm update cocos-obfuscator`
266
+ - npm 安装: `npm update cocos-obfuscator`
267
+
package/index.js ADDED
@@ -0,0 +1,361 @@
1
+ #!/usr/bin/env node
2
+
3
+ const JavaScriptObfuscator = require('javascript-obfuscator');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const readline = require('readline');
7
+
8
+ // 混淆配置 - 兼顾隐藏标识符/字符串与体积
9
+ const obfuscationOptions = {
10
+ compact: true, // 压缩输出
11
+ controlFlowFlattening: false, // 禁用控制流扁平化(大幅减少体积)
12
+ deadCodeInjection: false, // 禁用死代码注入(减少文件大小)
13
+ debugProtection: false, // 禁用调试保护(避免影响游戏运行)
14
+ disableConsoleOutput: false, // 不禁用console(游戏可能需要)
15
+ identifierNamesGenerator: 'mangled', // 更难读的标识符生成器
16
+ log: false, // 不输出日志
17
+ numbersToExpressions: false, // 禁用数字转表达式(减少体积)
18
+ renameGlobals: true, // 重命名全局变量以隐藏脚本名称
19
+ reservedNames: [ // 保留必要全局,避免运行错误
20
+ '^cc$', '^window$', '^document$', '^wx$', '^tt$', '^setTimeout$',
21
+ '^setInterval$', '^clearTimeout$', '^clearInterval$'
22
+ ],
23
+ selfDefending: false, // 关闭以减少体积并便于调试
24
+ simplify: true, // 简化代码
25
+ splitStrings: false, // 禁用字符串分割(减少体积)
26
+ stringArray: true, // 开启字符串数组以隐藏字符串文字(含文件名)
27
+ stringArrayThreshold: 0.05, // 较低阈值,平衡体积
28
+ stringArrayEncoding: ['base64'], // 编码字符串,避免直观暴露
29
+ stringArrayRotate: true, // 字符串数组旋转
30
+ stringArrayShuffle: true, // 字符串数组洗牌
31
+ stringArrayWrappersCount: 1, // 保持较低包装层数
32
+ transformObjectKeys: false, // 禁用对象键转换(避免破坏游戏)
33
+ unicodeEscapeSequence: false // 禁用unicode转义序列(减少体积)
34
+ };
35
+
36
+ // 混淆单个文件
37
+ function obfuscateFile(targetFile) {
38
+ // 检查文件是否存在
39
+ if (!fs.existsSync(targetFile)) {
40
+ console.warn('文件不存在,跳过:', targetFile);
41
+ return false;
42
+ }
43
+
44
+ const backupFile = targetFile + '.backup';
45
+
46
+ console.log('\n========================================');
47
+ console.log('开始混淆文件:', targetFile);
48
+
49
+ try {
50
+ // 读取原文件
51
+ const originalCode = fs.readFileSync(targetFile, 'utf8');
52
+
53
+ // 创建备份
54
+ fs.writeFileSync(backupFile, originalCode, 'utf8');
55
+ console.log('已创建备份文件:', backupFile);
56
+
57
+ // 执行混淆
58
+ const obfuscationResult = JavaScriptObfuscator.obfuscate(originalCode, obfuscationOptions);
59
+ const obfuscatedCode = obfuscationResult.getObfuscatedCode();
60
+
61
+ // 写入混淆后的代码
62
+ fs.writeFileSync(targetFile, obfuscatedCode, 'utf8');
63
+
64
+ console.log('混淆完成!');
65
+ console.log('原文件大小:', (originalCode.length / 1024).toFixed(2), 'KB');
66
+ console.log('混淆后大小:', (obfuscatedCode.length / 1024).toFixed(2), 'KB');
67
+ console.log('备份文件:', backupFile);
68
+
69
+ return true;
70
+
71
+ } catch (error) {
72
+ console.error('混淆过程中出现错误:', error);
73
+ console.log('正在恢复备份文件...');
74
+ if (fs.existsSync(backupFile)) {
75
+ const backupCode = fs.readFileSync(backupFile, 'utf8');
76
+ fs.writeFileSync(targetFile, backupCode, 'utf8');
77
+ }
78
+ return false;
79
+ }
80
+ }
81
+
82
+ // 交互式选择菜单
83
+ function interactiveSelect(options, question) {
84
+ return new Promise((resolve) => {
85
+ if (!process.stdin.isTTY) {
86
+ // 非交互式环境,使用默认值
87
+ console.log(question);
88
+ console.log('非交互式环境,使用默认值:', options[0].label);
89
+ resolve(options[0].value);
90
+ return;
91
+ }
92
+
93
+ let selectedIndex = 0;
94
+ let isResolved = false;
95
+
96
+ // 设置原始模式以捕获特殊按键
97
+ const wasRawMode = process.stdin.isRaw || false;
98
+ process.stdin.setRawMode(true);
99
+ process.stdin.resume();
100
+ process.stdin.setEncoding('utf8');
101
+
102
+ // 隐藏光标
103
+ process.stdout.write('\x1B[?25l');
104
+
105
+ // 显示菜单
106
+ function displayMenu() {
107
+ // 移动光标到开头并清除屏幕
108
+ process.stdout.write('\x1B[2J\x1B[H');
109
+ process.stdout.write(question + '\n');
110
+ process.stdout.write('使用 ↑↓ 键选择,Enter 确认\n\n');
111
+
112
+ options.forEach((option, index) => {
113
+ const prefix = index === selectedIndex ? '> ' : ' ';
114
+ const marker = index === selectedIndex ? '◉' : '○';
115
+ process.stdout.write(`${prefix}${marker} ${option.label}\n`);
116
+ });
117
+ }
118
+
119
+ displayMenu();
120
+
121
+ // 处理键盘输入
122
+ let buffer = '';
123
+ function onData(str) {
124
+ if (isResolved) return;
125
+
126
+ // 处理 Ctrl+C
127
+ if (str === '\u0003') {
128
+ cleanup();
129
+ process.exit(0);
130
+ return;
131
+ }
132
+
133
+ // 处理 Enter
134
+ if (str === '\r' || str === '\n') {
135
+ cleanup();
136
+ resolve(options[selectedIndex].value);
137
+ isResolved = true;
138
+ return;
139
+ }
140
+
141
+ // 处理箭头键
142
+ // 箭头键通常是转义序列:ESC [ A (上), ESC [ B (下)
143
+ // 在原始模式下,这些字符会逐个到达
144
+ buffer += str;
145
+
146
+ // 检查是否是完整的箭头键序列
147
+ if (buffer.length >= 3) {
148
+ // 上箭头: ESC [ A
149
+ if (buffer === '\u001b[A' || buffer.endsWith('\u001b[A')) {
150
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
151
+ displayMenu();
152
+ buffer = '';
153
+ return;
154
+ }
155
+ // 下箭头: ESC [ B
156
+ if (buffer === '\u001b[B' || buffer.endsWith('\u001b[B')) {
157
+ selectedIndex = (selectedIndex + 1) % options.length;
158
+ displayMenu();
159
+ buffer = '';
160
+ return;
161
+ }
162
+ // 如果不是箭头键序列,且缓冲区太长,清空
163
+ if (buffer.length > 10 || (!buffer.startsWith('\u001b') && buffer.length > 1)) {
164
+ buffer = '';
165
+ }
166
+ }
167
+ }
168
+
169
+ function cleanup() {
170
+ process.stdin.removeListener('data', onData);
171
+ process.stdin.setRawMode(wasRawMode);
172
+ process.stdin.pause();
173
+ // 显示光标
174
+ process.stdout.write('\x1B[?25h');
175
+ // 清屏
176
+ process.stdout.write('\x1B[2J\x1B[H');
177
+ }
178
+
179
+ process.stdin.on('data', onData);
180
+ });
181
+ }
182
+
183
+ // 解析命令行参数
184
+ function parseArgs() {
185
+ const args = process.argv.slice(2);
186
+ const config = {
187
+ platform: null, // null 表示需要交互式选择
188
+ includeSubpackages: null, // null 表示需要交互式选择
189
+ projectDir: null // 项目目录,默认为当前工作目录
190
+ };
191
+
192
+ for (let i = 0; i < args.length; i++) {
193
+ const arg = args[i];
194
+
195
+ if (arg === '--platform' && i + 1 < args.length) {
196
+ const platform = args[i + 1].toLowerCase();
197
+ if (platform === 'bytedance' || platform === 'bytedance-mini-game' || platform === 'wechatgame') {
198
+ config.platform = platform;
199
+ i++; // 跳过下一个参数
200
+ } else {
201
+ console.warn(`警告: 未知的平台 "${platform}",使用默认值 "bytedance"`);
202
+ config.platform = 'bytedance';
203
+ }
204
+ } else if (arg === '--include-subpackages' || arg === '--subpackages') {
205
+ config.includeSubpackages = true;
206
+ } else if (arg === '--no-subpackages') {
207
+ config.includeSubpackages = false;
208
+ } else if (arg === '--project-dir' && i + 1 < args.length) {
209
+ config.projectDir = args[i + 1];
210
+ i++;
211
+ } else if (arg === '--help' || arg === '-h') {
212
+ console.log(`
213
+ 用法: cocos-obfuscate [选项]
214
+
215
+ 选项:
216
+ --platform <平台> 指定平台: bytedance (2.x版本) 或 bytedance-mini-game (3.x版本) 或 wechatgame
217
+ --include-subpackages 包含分包文件进行混淆
218
+ --no-subpackages 不包含分包文件
219
+ --project-dir <目录> 指定项目目录(默认为当前目录)
220
+ --help, -h 显示此帮助信息
221
+
222
+ 如果不提供参数,将进入交互式选择模式。
223
+
224
+ 示例:
225
+ cocos-obfuscate --platform bytedance
226
+ cocos-obfuscate --platform bytedance-mini-game
227
+ cocos-obfuscate --platform wechatgame --include-subpackages
228
+ cocos-obfuscate (进入交互式选择)
229
+ `);
230
+ process.exit(0);
231
+ }
232
+ }
233
+
234
+ return config;
235
+ }
236
+
237
+ // 查找主包文件(文件名会变化,如 index.xxx.js)
238
+ function findMainIndexFile(projectDir, platform) {
239
+ const mainDir = path.join(projectDir, 'build', platform, 'assets', 'main');
240
+ if (!fs.existsSync(mainDir)) {
241
+ return null;
242
+ }
243
+
244
+ const files = fs.readdirSync(mainDir);
245
+ const indexFile = files.find(file => file.startsWith('index.') && file.endsWith('.js'));
246
+
247
+ if (indexFile) {
248
+ return path.join(mainDir, indexFile);
249
+ }
250
+
251
+ return null;
252
+ }
253
+
254
+ // 主函数
255
+ async function main() {
256
+ // 解析命令行参数
257
+ const config = parseArgs();
258
+ let platform = config.platform;
259
+ let includeSubpackages = config.includeSubpackages;
260
+ const projectDir = config.projectDir || process.cwd();
261
+
262
+ // 检查项目目录是否存在
263
+ if (!fs.existsSync(projectDir)) {
264
+ console.error('错误: 项目目录不存在:', projectDir);
265
+ process.exit(1);
266
+ }
267
+
268
+ // 如果没有通过命令行参数指定,则使用交互式选择
269
+ if (platform === null) {
270
+ const platformChoice = await interactiveSelect([
271
+ { label: 'bytedance (2.x 版本)', value: 'bytedance' },
272
+ { label: 'bytedance-mini-game (3.x 版本)', value: 'bytedance-mini-game' },
273
+ { label: 'wechatgame', value: 'wechatgame' }
274
+ ], '请选择平台:');
275
+ platform = platformChoice;
276
+ }
277
+
278
+ if (includeSubpackages === null) {
279
+ includeSubpackages = await interactiveSelect([
280
+ { label: '是', value: true },
281
+ { label: '否', value: false }
282
+ ], '是否包含分包文件?');
283
+ }
284
+
285
+ console.log('\n========================================');
286
+ console.log('混淆配置:');
287
+ console.log(' 项目目录:', projectDir);
288
+ console.log(' 平台:', platform);
289
+ console.log(' 包含分包:', includeSubpackages ? '是' : '否');
290
+ console.log('========================================\n');
291
+
292
+ const buildDir = path.join(projectDir, 'build', platform);
293
+
294
+ // 定义要混淆的文件列表
295
+ const filesToObfuscate = [];
296
+
297
+ // 添加主包文件(自动查找)
298
+ const mainIndexFile = findMainIndexFile(projectDir, platform);
299
+ if (mainIndexFile) {
300
+ filesToObfuscate.push(mainIndexFile);
301
+ console.log('找到主包文件:', mainIndexFile);
302
+ } else {
303
+ console.warn('警告: 未找到主包文件 build/' + platform + '/assets/main/index.xxx.js');
304
+ }
305
+
306
+ // 添加分包文件(如果启用)
307
+ if (includeSubpackages) {
308
+ const subpackages = [
309
+ 'com_new_v1/game.js',
310
+ 'for_sm/game.js',
311
+ 'for_wx/game.js',
312
+ 'remote_v1/game.js'
313
+ ];
314
+
315
+ subpackages.forEach(subpackage => {
316
+ const filePath = path.join(buildDir, 'subpackages', subpackage);
317
+ if (fs.existsSync(filePath)) {
318
+ filesToObfuscate.push(filePath);
319
+ console.log('找到分包文件:', filePath);
320
+ } else {
321
+ console.warn('警告: 分包文件不存在,跳过:', filePath);
322
+ }
323
+ });
324
+ }
325
+
326
+ // 执行混淆
327
+ console.log('\n准备混淆', filesToObfuscate.length, '个文件...\n');
328
+
329
+ if (filesToObfuscate.length === 0) {
330
+ console.error('错误: 没有找到需要混淆的文件!');
331
+ console.log('\n提示:');
332
+ console.log(' 1. 请检查 build/' + platform + ' 目录是否存在');
333
+ console.log(' 2. 确认已执行构建命令');
334
+ console.log(' 3. 使用 --help 查看使用说明');
335
+ process.exit(1);
336
+ }
337
+
338
+ let successCount = 0;
339
+ let failCount = 0;
340
+
341
+ filesToObfuscate.forEach((file, index) => {
342
+ if (obfuscateFile(file)) {
343
+ successCount++;
344
+ } else {
345
+ failCount++;
346
+ }
347
+ });
348
+
349
+ console.log('\n========================================');
350
+ console.log('混淆任务完成!');
351
+ console.log('成功:', successCount, '个文件');
352
+ console.log('失败:', failCount, '个文件');
353
+ console.log('\n提示: 如果游戏无法正常运行,可以使用备份文件(.backup)恢复');
354
+ }
355
+
356
+ // 运行主函数
357
+ main().catch(error => {
358
+ console.error('发生错误:', error);
359
+ process.exit(1);
360
+ });
361
+
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "cocos-obfuscator",
3
+ "version": "1.0.0",
4
+ "description": "Cocos Creator 项目代码混淆工具,支持字节跳动小游戏和微信小游戏平台",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "cocos-obfuscate": "./index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "cocos",
14
+ "cocos-creator",
15
+ "obfuscator",
16
+ "javascript-obfuscator",
17
+ "bytedance",
18
+ "wechatgame",
19
+ "miniprogram"
20
+ ],
21
+ "author": "habehe",
22
+ "license": "ISC",
23
+ "dependencies": {
24
+ "javascript-obfuscator": "^4.1.1"
25
+ },
26
+ "engines": {
27
+ "node": ">=12.0.0"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": ""
32
+ }
33
+ }
34
+