@flun/node-mobile-app 4.0.4 → 4.0.6

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.
@@ -1,348 +1,347 @@
1
- # Android 构建指南
2
-
3
- 本文档是 [README.md](./README.md) 的**深度附件**;日常使用(`test` / `build`)不需要看——CLI 自动处理;
4
-
5
- 本文档只讲四件事,都是 README 没细说的:
6
- 1. **环境准备**(JDK / SDK / NDK / adb / 原生模块编译)
7
- 2. **libnode.so**(v18 vs v22、预编译仓库、替换、full-icu 验证)
8
- 3. **Express 版本选择**(踩坑清单)
9
- 4. **调试与缓存排查**(logcat 命令、手动清缓存兜底)
10
-
11
- ---
12
-
13
- ## 一、环境准备
14
-
15
- ### 1.1 JDK 17(必须)
16
-
17
- Android Gradle Plugin 不支持 JDK 18+;
18
-
19
- 下载:[Adoptium JDK 17](https://adoptium.net/temurin/releases/?version=17)
20
-
21
- **CLI 不读 `JAVA_HOME`**,直接用系统 PATH 里的 `java`;确保 `java -version` 输出是 17;
22
-
23
- ### 1.2 Android SDK
24
-
25
- CLI 自动查找,顺序:
26
-
27
- 1. `mobileAppConfig.js` 的 `android.sdkPath`
28
- 2. 环境变量 `ANDROID_HOME` / `ANDROID_SDK_ROOT`
29
- 3. 常见默认路径(Windows:`%LOCALAPPDATA%\Android\Sdk`)
30
-
31
- **必需组件**:
32
-
33
- | 组件 | 版本 |
34
- | -------------- | ------------------------------------ |
35
- | SDK Platform | 36 |
36
- | Build-Tools | 37.0.0 |
37
- | Platform-Tools | 最新(含 adb) |
38
- | NDK | 27.1.12297006(libnode.so 编译依赖) |
39
-
40
- ### 1.3 adb
41
-
42
- 查找顺序同 SDK;常用命令:
43
-
44
- ```powershell
45
- $adb = "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe"
46
- & $adb devices
47
- ```
48
-
49
- ### 1.4 原生模块编译(自动检测)
50
-
51
- CLI 会扫描 `<buildDir>/nodejs-assets/nodejs-project/node_modules/` 下是否有 `binding.gyp` 文件(原生模块的标志),自动写:
52
-
53
- ```
54
- <buildDir>/nodejs-assets/BUILD_NATIVE_MODULES.txt # 1=有原生模块,0=无
55
- ```
56
-
57
- - **检测到原生模块**(如 `bcrypt`、`sqlite3`):写 `1`,并设环境变量 `NODEJS_MOBILE_BUILD_NATIVE_MODULES=1`,`npm install` 时自动重编
58
- - **未检测到**:写 `0`,跳过编译
59
-
60
- **用户无需手动配置**;检测结果会纳入依赖哈希,装/卸原生模块时会自动触发重装重编;
61
-
62
- **手动强制重编**:换过 `libnode.so` 但依赖没变、需要重新编译原生模块时:
63
-
64
- ```bash
65
- # Linux / macOS
66
- NODE_MOBILE_FORCE_REBUILD=1 npx node-mobile-app test
67
- ```
68
-
69
- ```powershell
70
- # Windows
71
- $env:NODE_MOBILE_FORCE_REBUILD=1; npx node-mobile-app test
72
- ```
73
-
74
- **平台限制**:Windows 上 nodejs-mobile 无法编译原生模块(上游限制);此功能仅 Linux / macOS 可用;
75
-
76
- ---
77
-
78
- ## 二、libnode.so
79
-
80
- `nodejs-mobile-react-native` 用它提供 Node.js 运行时;**是否带 full-icu** 决定能跑哪个 Express 版本;
81
-
82
- ### 2.0 预编译二进制怎么来的
83
-
84
- 从 `@flun/nodejs-mobile-react-native` 1.0.1 起,`libnode.so` **不在 npm 包里**,安装时由 postinstall 脚本从 Gitee / GitHub Release 自动下载:
85
-
86
- - **下载源**:Gitee 优先,失败自动回退 GitHub
87
- - **下载内容**:`android-libnode.zip`(约 52 MB),含 `bin/` + `include/`
88
- - **覆盖目标**:`node_modules/@flun/nodejs-mobile-react-native/android/libnode/`
89
- - **幂等**:已装版本匹配则跳过,不重复下载
90
- - **失败处理**:全部源失败时打印下载链接,不中断 npm 安装
91
-
92
- 环境变量(按需):
93
-
94
- ```bash
95
- NODE_MOBILE_PREBUILT_VERSION=v22.23.2 # 覆盖默认版本
96
- NODE_MOBILE_PREBUILT_SKIP=1 # 跳过全部下载
97
- NODE_MOBILE_PREBUILT_ANDROID_SKIP=1 # 只跳过 Android
98
- ```
99
-
100
- **用户不需要手动下载和替换**——除非要换成自编译的版本,见 2.2;
101
-
102
- ### 2.1 官方 v18(默认自动下载)
103
-
104
- 路径:
105
-
106
- ```
107
- <你的项目>/node_modules/@flun/nodejs-mobile-react-native/android/libnode/bin/<架构>/libnode.so
108
- ```
109
-
110
- | 架构 | 大小 |
111
- | ----------- | ------- |
112
- | arm64-v8a | 59.6 MB |
113
- | armeabi-v7a | 56 MB |
114
- | x86_64 | 62.3 MB |
115
-
116
- **特点**:`--with-intl=none`,**不含 ICU**;
117
-
118
- - 不能用 `\p{...}` / `\P{...}` Unicode 正则
119
- - **必须 Express 4**
120
-
121
- ### 2.2 自编译 v22+(推荐)
122
-
123
- **官方 v18 已停更**;要跑 Express 5 或新语法,需替换;
124
-
125
- **预编译产物仓库**:
126
-
127
- - GitHub:https://github.com/OpenFlun/nodejs-mobile
128
- - Gitee(国内):https://gitee.com/OpenFlun/nodejs-mobile
129
-
130
- **当前 Android 支持情况**:
131
-
132
- | 架构 | v18 | v22 |
133
- | ----------- | --- | --- |
134
- | arm64-v8a | ✓ | ✓ |
135
- | x86_64 | ✓ | ✓ |
136
- | armeabi-v7a | ✓ | ✗ |
137
-
138
- **未来计划**:v24、v26 逐步适配;
139
-
140
- **替换步骤**:
141
-
142
- 1. 下载 `libnode.zip`(含 `bin/` + `include/`)
143
- 2. **整体替换** `你的项目/node_modules/@flun/nodejs-mobile-react-native/android/libnode/`
144
- 3. `mobileAppConfig.js` 的 `android.abiFilters` 只写实际存在的架构(v22 是 `['arm64-v8a', 'x86_64']`)
145
- 4. 跑 `npx node-mobile-app test` 或 `build`
146
-
147
- CLI 指纹机制会自动清 `.cxx` / `android/build` / `app/build` 并全量重编——**无需手动清缓存**;
148
-
149
- **完整自编译流程**见 `自定义libnode指南.md`;
150
-
151
- ### 2.3 验证是否带 full-icu
152
-
153
- ```bash
154
- # Linux / macOS / WSL / Git Bash
155
- strings libnode.so | grep -c icudt78l
156
- ```
157
-
158
- - 输出几千(约 4300)→ 带 full-icu
159
- - 输出 0 → 不带
160
-
161
- **体积对照**(实测,strip 后):
162
-
163
- | 版本 | arm64-v8a | x86_64 |
164
- | ---------------------- | --------- | -------- |
165
- | v18(官方,无 ICU) | 59.6 MB | 62.3 MB |
166
- | v22(自编译,full-icu) | 112.4 MB | 117.2 MB |
167
-
168
- 体积差异约 50 MB,来自三部分:Node v22 核心引擎 + full-icu 数据(约 25–30 MB)+ V8 版本升级;**不是编译出错**;
169
-
170
- ---
171
-
172
- ## 三、Express 版本选择(踩坑清单)
173
-
174
- **选错版本会在 Node 进程启动时崩溃**,且错误信息极具误导性(如 `number 116 is not a function`);
175
-
176
- ### 3.1 版本对照
177
-
178
- | libnode.so | Node.js | ICU | Express |
179
- | --------------------- | ------- | --- | ---------------------- |
180
- | 官方 v18 | v18 | 无 | **4.x**(如 `4.22.2`) |
181
- | 自编译 v22 + full-icu | v22 | 有 | **5.x**(如 `5.2.1`) |
182
-
183
- ### 3.2 场景 A(v18 + Express 4)
184
-
185
- `nodejs-project/package.json`:
186
-
187
- ```json
188
- {
189
- "dependencies": {
190
- "express": "4.22.2"
191
- }
192
- }
193
- ```
194
-
195
- 依赖里如有 `\P{ASCII}` 等 Unicode 正则,改写成 ASCII 等价:
196
-
197
- | 原写法 | ASCII 写法 |
198
- | ----------- | -------------- |
199
- | `\P{ASCII}` | `[^\x00-\x7F]` |
200
-
201
- ### 3.3 场景 B(v22 + full-icu + Express 5)
202
-
203
- ```json
204
- {
205
- "dependencies": {
206
- "express": "5.2.1"
207
- }
208
- }
209
- ```
210
-
211
- **三个前提**:
212
-
213
- 1. `libnode.so` 确实带 full-icu(用 `strings` 验证过)
214
- 2. **不要**用 `@alloc/path-to-regexp` 替换原版——它的 `exports` 只有 `import` 条件,CJS 下 `require()` 报 `No "exports" main defined`
215
- 3. **不要**加任何 `overrides` 强制替换 `path-to-regexp`
216
-
217
- ### 3.4 Express 5 路由语法迁移
218
-
219
- `app.get('*')` 会抛 `TypeError: Missing parameter name`:
220
-
221
- | Express 4 | Express 5 |
222
- | ---------------------------- | --------------------------------- |
223
- | `app.get('*', handler)` | `app.get('/{*splat}', handler)` |
224
- | `app.get('/:id?', handler)` | `app.get('/user{/:id}', handler)` |
225
- | `app.get('/:id(\\d+)', ...)` | 中间件校验 `req.params.id` |
226
- | `app.del('/x', handler)` | `app.delete('/x', handler)` |
227
- | `res.json(obj, 200)` | `res.status(200).json(obj)` |
228
- | `res.send(200, body)` | `res.status(200).send(body)` |
229
-
230
- ### 3.5 验证依赖树
231
-
232
- ```powershell
233
- cd node-mobile-app-build\nodejs-assets\nodejs-project
234
- npm ls express --all
235
- npm ls path-to-regexp --all
236
- ```
237
-
238
- **期望(场景 B)**:
239
-
240
- ```
241
- express@5.2.1
242
- └─┬ router@2.2.0
243
- └── path-to-regexp@8.4.2
244
- ```
245
-
246
- 如出现 `@alloc/path-to-regexp`,说明 `package-lock.json` 里有残留 `overrides`;**彻底清理**:
247
-
248
- ```powershell
249
- Remove-Item -Recurse -Force node_modules, package-lock.json
250
- npm install
251
- ```
252
-
253
- ### 3.6 三个常见误区
254
-
255
- - **误区 1**:以为 `@alloc/path-to-regexp` 能解决 ESM 问题 → 它的 `exports` 也是纯 `import`,`require()` 依然失败
256
- - **误区 2**:只改路由语法就想让 Express 5 跑 → 若 `libnode.so` 无 full-icu,加载 `path-to-regexp@8` 时仍崩
257
- - **误区 3**:用 `overrides` 强制替换 `path-to-regexp` → 破坏依赖链,且 `package-lock.json` 会残留解析结果,删掉 `overrides` 也不生效
258
-
259
- ---
260
-
261
- ## 四、调试与缓存排查
262
-
263
- ### 4.1 抓 Node.js 日志
264
-
265
- ```powershell
266
- $adb = "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe"
267
-
268
- # 清空
269
- & $adb logcat -c
270
-
271
- # 重启 App
272
- & $adb shell am force-stop com.me.myapp
273
- & $adb shell am start -n com.me.myapp/.MainActivity
274
-
275
- # 抓关键日志
276
- & $adb logcat -d | Select-String 'NODEJS-MOBILE|ReactNativeJS'
277
- ```
278
-
279
- **正常日志**:
280
- ```
281
- NODEJS-MOBILE: [node-mobile-app] server URL: http://127.0.0.1:3000
282
- NODEJS-MOBILE: Express started on port 3000
283
- ReactNativeJS: Node started on http://127.0.0.1:3000
284
- ```
285
-
286
- **失败日志**:
287
- ```
288
- NODEJS-MOBILE: [node-mobile-app] failed: Node 服务 5 秒内未启动 -- 请检查 ./server.js 是否调用了 listen()
289
- ```
290
-
291
- **崩溃日志**:
292
-
293
- ```powershell
294
- & $adb logcat -c
295
- & $adb logcat | Select-String 'FATAL|AndroidRuntime|NODEJS-MOBILE'
296
- ```
297
-
298
- ### 4.2 手动清缓存(兜底)
299
-
300
- **正常情况不需要**——CLI 指纹机制自动清;以下仅当指纹判断失效(如手动改过 `node-mobile-app-build/` 内文件)时用:
301
-
302
- ```powershell
303
- # 最彻底:删整个 RN 工程
304
- Remove-Item -Recurse -Force D:\你的项目\node-mobile-app-build
305
-
306
- # 或删插件 CMake 缓存
307
- Remove-Item -Recurse -Force D:\你的项目\node_modules\@flun\nodejs-mobile-react-native\android\.cxx
308
- Remove-Item -Recurse -Force D:\你的项目\node_modules\@flun\nodejs-mobile-react-native\android\build
309
-
310
- # 或删指纹文件(下次跑 = 全新构建)
311
- Remove-Item -Force D:\你的项目\node-mobile-app-build\.build-fingerprint.json
312
- ```
313
-
314
- 或直接:
315
-
316
- ```powershell
317
- npx node-mobile-app clean
318
- ```
319
-
320
- ### 4.3 手动端口转发(`test` 会自动做)
321
-
322
- ```powershell
323
- & "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" reverse tcp:8081 tcp:8081
324
- & "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" reverse --list
325
- ```
326
-
327
- ### 4.4 模拟器(x86_64)
328
-
329
- ```powershell
330
- # 列出 AVD
331
- & "$env:LOCALAPPDATA\Android\Sdk\emulator\emulator.exe" -list-avds
332
-
333
- # 启动
334
- & "$env:LOCALAPPDATA\Android\Sdk\emulator\emulator.exe" -avd Pixel_7_API_34
335
- ```
336
-
337
- **三个必须**:
338
- - `mobileAppConfig.js` 的 `abiFilters` 含 `x86_64`
339
- - `libnode/bin/x86_64/libnode.so` 存在
340
- - 模拟器镜像是 **x86_64 架构**
341
-
342
- ---
343
-
344
- ## 相关文档
345
-
346
- - [README.md](./README.md) —— 快速开始、配置字段、命令
347
- - [自定义libnode指南.md](./自定义libnode指南.md) —— 自编译 v22 + full-icu 完整流程
348
- - [libnode.so 预编译仓库](https://github.com/OpenFlun/nodejs-mobile)([Gitee](https://gitee.com/OpenFlun/nodejs-mobile))
1
+ # Android 构建指南
2
+
3
+ 本文档是 [README.md](./README.md) 的**深度附件**;日常使用(`test` / `build`)不需要看——CLI 自动处理;
4
+
5
+ 本文档只讲四件事,都是 README 没细说的:
6
+ 1. **环境准备**(JDK / SDK / NDK / adb / 原生模块编译)
7
+ 2. **libnode.so**(v18 vs v22、预编译仓库、替换、full-icu 验证)
8
+ 3. **Express 版本选择**(踩坑清单)
9
+ 4. **调试与缓存排查**(logcat 命令、手动清缓存兜底)
10
+
11
+ ---
12
+
13
+ ## 一、环境准备
14
+
15
+ ### 1.1 JDK 17(必须)
16
+
17
+ Android Gradle Plugin 不支持 JDK 18+;
18
+
19
+ 下载:[Adoptium JDK 17](https://adoptium.net/temurin/releases/?version=17)
20
+
21
+ **CLI 不读 `JAVA_HOME`**,直接用系统 PATH 里的 `java`;确保 `java -version` 输出是 17;
22
+
23
+ ### 1.2 Android SDK
24
+
25
+ CLI 自动查找,顺序:
26
+
27
+ 1. `mobileAppConfig.js` 的 `android.sdkPath`
28
+ 2. 环境变量 `ANDROID_HOME` / `ANDROID_SDK_ROOT`
29
+ 3. 常见默认路径(Windows:`%LOCALAPPDATA%\Android\Sdk`)
30
+
31
+ **必需组件**:
32
+
33
+ | 组件 | 版本 |
34
+ | -------------- | ------------------------------------------------------------------------- |
35
+ | SDK Platform | 与 `mobileAppConfig.js` 的 `android.compileSdkVersion` 一致的 Platform |
36
+ | Build-Tools | 与 `mobileAppConfig.js` 的 `android.buildToolsVersion` 一致 |
37
+ | Platform-Tools | 含 adb 的较新版本 |
38
+ | NDK | 与模板 `android/build.gradle` 的 `ndkVersion` 一致(libnode.so 编译依赖) |
39
+
40
+ ### 1.3 adb
41
+
42
+ 查找顺序同 SDK;常用命令:
43
+
44
+ ```powershell
45
+ $adb = "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe"
46
+ & $adb devices
47
+ ```
48
+
49
+ ### 1.4 原生模块编译(自动检测)
50
+
51
+ CLI 会扫描 `<buildDir>/nodejs-assets/nodejs-project/node_modules/` 下是否有 `binding.gyp` 文件(原生模块的标志),自动写:
52
+
53
+ ```
54
+ <buildDir>/nodejs-assets/BUILD_NATIVE_MODULES.txt # 1=有原生模块,0=无
55
+ ```
56
+
57
+ - **检测到原生模块**(如 `bcrypt`、`sqlite3`):写 `1`,并设环境变量 `NODEJS_MOBILE_BUILD_NATIVE_MODULES=1`,`npm install` 时自动重编
58
+ - **未检测到**:写 `0`,跳过编译
59
+
60
+ **用户无需手动配置**;检测结果会纳入依赖哈希,装/卸原生模块时会自动触发重装重编;
61
+
62
+ **手动强制重编**:换过 `libnode.so` 但依赖没变、需要重新编译原生模块时:
63
+
64
+ ```bash
65
+ # Linux / macOS
66
+ NODE_MOBILE_FORCE_REBUILD=1 npx node-mobile-app test
67
+ ```
68
+
69
+ ```powershell
70
+ # Windows
71
+ $env:NODE_MOBILE_FORCE_REBUILD=1; npx node-mobile-app test
72
+ ```
73
+
74
+ **Windows 编译原生模块的前置条件**:需 Android SDK 中的 NDK(提供交叉编译工具链与 `make.exe`)与 Git for Windows(提供 `sh` / `sed` / `rm` 等 GNU 工具,`nodejs-mobile-gyp` 会从注册表或常见路径自动定位);二者缺失时编译阶段报错;Linux / macOS 使用系统自带的同类工具,无需额外安装;
75
+
76
+ ---
77
+
78
+ ## 二、libnode.so
79
+
80
+ `nodejs-mobile-react-native` 用它提供 Node.js 运行时;**是否带 full-icu** 决定能跑哪个 Express 版本;
81
+
82
+ ### 2.0 预编译二进制怎么来的
83
+
84
+ 从 `@flun/nodejs-mobile-react-native` 1.0.1 起,`libnode.so` **不在 npm 包里**,安装时由 postinstall 脚本从 Gitee / GitHub Release 自动下载:
85
+
86
+ - **下载源**:Gitee 优先,失败自动回退 GitHub
87
+ - **下载内容**:`android-libnode.zip`(双架构约 88 MB),含 `bin/` + `include/`;具体大小以实际下载为准;
88
+ - **覆盖目标**:`node_modules/@flun/nodejs-mobile-react-native/android/libnode/`
89
+ - **幂等**:已装版本匹配则跳过,不重复下载
90
+ - **失败处理**:全部源失败时打印下载链接,不中断 npm 安装
91
+
92
+ 环境变量(按需):
93
+
94
+ ```bash
95
+ NODE_MOBILE_PREBUILT_VERSION=v22.23.2 # 覆盖默认版本
96
+ NODE_MOBILE_PREBUILT_SKIP=1 # 跳过全部下载
97
+ NODE_MOBILE_PREBUILT_ANDROID_SKIP=1 # 只跳过 Android
98
+ ```
99
+
100
+ **用户不需要手动下载和替换**——除非要换成自编译的版本,见 2.2;
101
+
102
+ ### 2.1 自动下载的预编译产物
103
+
104
+ 路径:
105
+
106
+ ```
107
+ <你的项目>/node_modules/@flun/nodejs-mobile-react-native/android/libnode/bin/<架构>/libnode.so
108
+ ```
109
+
110
+ 以下为 v18 产物的实测大小;其它版本的体积以实际下载为准:
111
+
112
+ | 架构 | 大小 |
113
+ | ----------- | ------- |
114
+ | arm64-v8a | 59.6 MB |
115
+ | armeabi-v7a | 56 MB |
116
+ | x86_64 | 62.3 MB |
117
+
118
+ **版本特性**:v18 产物使用 `--with-intl=none`,不含 ICU,不能用 `\p{...}` / `\P{...}` Unicode 正则,必须配 Express 4;v22 起产物带 full-icu,可用 Unicode 正则与 Express 5;下载版本由 `package.json` 的 `prebuiltAssets.version` 决定;
119
+
120
+ ### 2.2 替换为自编译产物
121
+
122
+ 自动下载的产物若不含 full-icu(见 2.3 的 `strings` 验证),且需跑 Express 5 或使用 Unicode 正则,替换为自编译的 full-icu 版本;
123
+
124
+ **预编译产物仓库**:
125
+
126
+ - GitHub:https://github.com/OpenFlun/nodejs-mobile
127
+ - Gitee(国内):https://gitee.com/OpenFlun/nodejs-mobile
128
+
129
+ **架构支持(按版本)**:
130
+
131
+ | 架构 | v18 | v22 |
132
+ | ----------- | --- | --- |
133
+ | arm64-v8a | ✓ | ✓ |
134
+ | x86_64 | ✓ | ✓ |
135
+ | armeabi-v7a | ✓ | ✗ |
136
+
137
+ 架构支持随产物版本变化;具体以 Releases 页面各版本的产物说明为准;
138
+
139
+ **替换步骤**:
140
+
141
+ 1. 下载 `android-libnode.zip`(含 `bin/` + `include/`)
142
+ 2. **整体替换** `你的项目/node_modules/@flun/nodejs-mobile-react-native/android/libnode/`
143
+ 3. `mobileAppConfig.js` 的 `android.abiFilters` 只写该产物实际包含的架构(见解压后的 `libnode/bin/` 目录)
144
+ 4. 跑 `npx node-mobile-app test` 或 `build`
145
+
146
+ CLI 指纹机制检测到 `libnode.so` 变化后,会清 `.cxx` / `android/build` / `app/build`,并清 `nodejs-assets` 与依赖快照,触发重装、重编、重优化——**无需手动清缓存**;
147
+
148
+ **完整自编译流程**见 `自定义libnode指南.md`;
149
+
150
+ ### 2.3 验证是否带 full-icu
151
+
152
+ ```bash
153
+ # Linux / macOS / WSL / Git Bash
154
+ strings libnode.so | grep -c icudt78l
155
+ ```
156
+
157
+ - 输出几千(约 4300)→ 带 full-icu
158
+ - 输出 0 → 不带
159
+
160
+ **体积对照**(实测,strip 后):
161
+
162
+ | 版本 | arm64-v8a | x86_64 |
163
+ | ---------------------- | --------- | -------- |
164
+ | v18(官方,无 ICU) | 59.6 MB | 62.3 MB |
165
+ | v22(自编译,full-icu) | 112.4 MB | 117.2 MB |
166
+
167
+ 体积差异约 50 MB,来自三部分:Node v22 核心引擎 + full-icu 数据(约 25–30 MB)+ V8 版本升级;**不是编译出错**;
168
+
169
+ ---
170
+
171
+ ## 三、Express 版本选择(踩坑清单)
172
+
173
+ **选错版本会在 Node 进程启动时崩溃**,且错误信息极具误导性(如 `number 116 is not a function`);
174
+
175
+ ### 3.1 版本对照
176
+
177
+ | libnode.so | Node.js | ICU | Express |
178
+ | --------------------- | ------- | --- | ---------------------- |
179
+ | 官方 v18 | v18 | 无 | **4.x**(如 `4.22.2`) |
180
+ | 自编译 v22 + full-icu | v22 | 有 | **5.x**(如 `5.2.1`) |
181
+
182
+ ### 3.2 场景 A(v18 + Express 4)
183
+
184
+ `nodejs-project/package.json`:
185
+
186
+ ```json
187
+ {
188
+ "dependencies": {
189
+ "express": "4.22.2"
190
+ }
191
+ }
192
+ ```
193
+
194
+ 依赖里如有 `\P{ASCII}` 等 Unicode 正则,改写成 ASCII 等价:
195
+
196
+ | 原写法 | ASCII 写法 |
197
+ | ----------- | -------------- |
198
+ | `\P{ASCII}` | `[^\x00-\x7F]` |
199
+
200
+ ### 3.3 场景 B(v22 + full-icu + Express 5)
201
+
202
+ ```json
203
+ {
204
+ "dependencies": {
205
+ "express": "5.2.1"
206
+ }
207
+ }
208
+ ```
209
+
210
+ **三个前提**:
211
+
212
+ 1. `libnode.so` 确实带 full-icu(用 `strings` 验证过)
213
+ 2. **不要**用 `@alloc/path-to-regexp` 替换原版——它的 `exports` 只有 `import` 条件,CJS 下 `require()` 报 `No "exports" main defined`
214
+ 3. **不要**加任何 `overrides` 强制替换 `path-to-regexp`
215
+
216
+ ### 3.4 Express 5 路由语法迁移
217
+
218
+ `app.get('*')` 会抛 `TypeError: Missing parameter name`:
219
+
220
+ | Express 4 | Express 5 |
221
+ | ---------------------------- | --------------------------------- |
222
+ | `app.get('*', handler)` | `app.get('/{*splat}', handler)` |
223
+ | `app.get('/:id?', handler)` | `app.get('/user{/:id}', handler)` |
224
+ | `app.get('/:id(\\d+)', ...)` | 中间件校验 `req.params.id` |
225
+ | `app.del('/x', handler)` | `app.delete('/x', handler)` |
226
+ | `res.json(obj, 200)` | `res.status(200).json(obj)` |
227
+ | `res.send(200, body)` | `res.status(200).send(body)` |
228
+
229
+ ### 3.5 验证依赖树
230
+
231
+ ```powershell
232
+ cd node-mobile-app-build\nodejs-assets\nodejs-project
233
+ npm ls express --all
234
+ npm ls path-to-regexp --all
235
+ ```
236
+
237
+ **期望(场景 B)**:
238
+
239
+ ```
240
+ express@5.2.1
241
+ └─┬ router@2.2.0
242
+ └── path-to-regexp@8.4.2
243
+ ```
244
+
245
+ 如出现 `@alloc/path-to-regexp`,说明 `package-lock.json` 里有残留 `overrides`;**彻底清理**:
246
+
247
+ ```powershell
248
+ Remove-Item -Recurse -Force node_modules, package-lock.json
249
+ npm install
250
+ ```
251
+
252
+ ### 3.6 三个常见误区
253
+
254
+ - **误区 1**:以为 `@alloc/path-to-regexp` 能解决 ESM 问题 → 它的 `exports` 也是纯 `import`,`require()` 依然失败
255
+ - **误区 2**:只改路由语法就想让 Express 5 跑 → 若 `libnode.so` 无 full-icu,加载 `path-to-regexp@8` 时仍崩
256
+ - **误区 3**:用 `overrides` 强制替换 `path-to-regexp` → 破坏依赖链,且 `package-lock.json` 会残留解析结果,删掉 `overrides` 也不生效
257
+
258
+ ---
259
+
260
+ ## 四、调试与缓存排查
261
+
262
+ ### 4.1 抓 Node.js 日志
263
+
264
+ ```powershell
265
+ $adb = "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe"
266
+
267
+ # 清空
268
+ & $adb logcat -c
269
+
270
+ # 重启 App
271
+ & $adb shell am force-stop com.me.myapp
272
+ & $adb shell am start -n com.me.myapp/.MainActivity
273
+
274
+ # 抓关键日志
275
+ & $adb logcat -d | Select-String 'NODEJS-MOBILE|ReactNativeJS'
276
+ ```
277
+
278
+ **正常日志**:
279
+ ```
280
+ NODEJS-MOBILE: [node-mobile-app] server URL: http://127.0.0.1:3000
281
+ NODEJS-MOBILE: Express started on port 3000
282
+ ReactNativeJS: Node started on http://127.0.0.1:3000
283
+ ```
284
+
285
+ **失败日志**:
286
+ ```
287
+ NODEJS-MOBILE: [node-mobile-app] failed: Node 服务 5 秒内未启动 -- 请检查 ./server.js 是否调用了 listen()
288
+ ```
289
+
290
+ **崩溃日志**:
291
+
292
+ ```powershell
293
+ & $adb logcat -c
294
+ & $adb logcat | Select-String 'FATAL|AndroidRuntime|NODEJS-MOBILE'
295
+ ```
296
+
297
+ ### 4.2 手动清缓存(兜底)
298
+
299
+ **正常情况不需要**——CLI 指纹机制自动清;以下仅当指纹判断失效(如手动改过 `node-mobile-app-build/` 内文件)时用:
300
+
301
+ ```powershell
302
+ # 最彻底:删整个 RN 工程
303
+ Remove-Item -Recurse -Force D:\你的项目\node-mobile-app-build
304
+
305
+ # 或删插件 CMake 缓存
306
+ Remove-Item -Recurse -Force D:\你的项目\node_modules\@flun\nodejs-mobile-react-native\android\.cxx
307
+ Remove-Item -Recurse -Force D:\你的项目\node_modules\@flun\nodejs-mobile-react-native\android\build
308
+
309
+ # 或删指纹文件(下次跑 = 全新构建)
310
+ Remove-Item -Force D:\你的项目\node-mobile-app-build\.build-fingerprint.json
311
+ ```
312
+
313
+ 或直接:
314
+
315
+ ```powershell
316
+ npx node-mobile-app clean
317
+ ```
318
+
319
+ ### 4.3 手动端口转发(`test` 会自动做)
320
+
321
+ ```powershell
322
+ & "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" reverse tcp:8081 tcp:8081
323
+ & "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" reverse --list
324
+ ```
325
+
326
+ ### 4.4 模拟器(x86_64)
327
+
328
+ ```powershell
329
+ # 列出 AVD
330
+ & "$env:LOCALAPPDATA\Android\Sdk\emulator\emulator.exe" -list-avds
331
+
332
+ # 启动
333
+ & "$env:LOCALAPPDATA\Android\Sdk\emulator\emulator.exe" -avd Pixel_7_API_34
334
+ ```
335
+
336
+ **三个必须**:
337
+ - `mobileAppConfig.js` 的 `abiFilters` 含 `x86_64`
338
+ - `libnode/bin/x86_64/libnode.so` 存在
339
+ - 模拟器镜像是 **x86_64 架构**
340
+
341
+ ---
342
+
343
+ ## 相关文档
344
+
345
+ - [README.md](./README.md) —— 快速开始、配置字段、命令
346
+ - [自定义libnode指南.md](./自定义libnode指南.md) —— 自编译 v22 + full-icu 完整流程
347
+ - [libnode.so 预编译仓库](https://github.com/OpenFlun/nodejs-mobile)([Gitee](https://gitee.com/OpenFlun/nodejs-mobile))