@flun/node-mobile-app 2.1.1 → 3.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.
- package/Android /346/236/204/345/273/272/346/214/207/345/215/227.md" +1 -1
- package/CHANGELOG.md +34 -32
- package/README.md +36 -7
- package/bin/cli.js +11 -10
- package/mobileAppConfig.js +10 -0
- package/package.json +15 -13
- package/scripts/copy-files.js +24 -25
- package/src/commands/build.js +19 -14
- package/src/commands/clean.js +6 -2
- package/src/commands/test.js +26 -25
- package/src/config.js +6 -1
- package/src/copy.js +8 -23
- package/src/fingerprint.js +28 -8
- package/src/install.js +100 -55
- package/src/optimize-node-modules.js +698 -0
- package/src/patcher.js +21 -24
- package/src/platform-ios.js +139 -141
- package/src/utils.js +189 -176
package/src/copy.js
CHANGED
|
@@ -34,7 +34,7 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
34
34
|
copyDirIncremental = (src, dst, exclude) => {
|
|
35
35
|
ensureDir(dst);
|
|
36
36
|
|
|
37
|
-
const dstKeep = new Set(['node_modules', '
|
|
37
|
+
const dstKeep = new Set(['node_modules', 'main.js', 'package.json', 'package-lock.json']),
|
|
38
38
|
srcNames = new Set(fs.readdirSync(src));
|
|
39
39
|
// 1. 删除 dst 里不该存在的条目
|
|
40
40
|
for (const name of fs.readdirSync(dst)) {
|
|
@@ -66,36 +66,23 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
66
66
|
if (!fs.existsSync(buildPkgPath)) return;
|
|
67
67
|
const mainPkgPath = path.join(pkgRoot, 'package.json');
|
|
68
68
|
if (!fs.existsSync(mainPkgPath)) return;
|
|
69
|
-
|
|
70
|
-
const buildPkg = readJson(buildPkgPath);
|
|
71
|
-
const mainPkg = readJson(mainPkgPath);
|
|
69
|
+
const buildPkg = readJson(buildPkgPath), mainPkg = readJson(mainPkgPath);
|
|
72
70
|
if (!buildPkg.dependencies) return;
|
|
73
71
|
|
|
74
|
-
const mainDeps = mainPkg.dependencies || {};
|
|
75
|
-
|
|
76
|
-
let depsUpdated = 0;
|
|
77
|
-
let needWrite = false;
|
|
72
|
+
const mainDeps = mainPkg.dependencies || {}, missing = [];
|
|
73
|
+
let depsUpdated = 0, needWrite = false;
|
|
78
74
|
|
|
79
75
|
// 移除仅用于模板占位说明的 _comment 字段,避免带进最终 build 工程
|
|
80
|
-
if ('_comment' in buildPkg)
|
|
81
|
-
delete buildPkg._comment;
|
|
82
|
-
needWrite = true;
|
|
83
|
-
}
|
|
76
|
+
if ('_comment' in buildPkg) delete buildPkg._comment, needWrite = true;
|
|
84
77
|
for (const name of Object.keys(buildPkg.dependencies)) {
|
|
85
78
|
const v = mainDeps[name];
|
|
86
79
|
if (!v) { missing.push(name); continue; }
|
|
87
|
-
if (buildPkg.dependencies[name] !== v)
|
|
88
|
-
buildPkg.dependencies[name] = v;
|
|
89
|
-
depsUpdated++;
|
|
90
|
-
needWrite = true;
|
|
91
|
-
}
|
|
80
|
+
if (buildPkg.dependencies[name] !== v) buildPkg.dependencies[name] = v, depsUpdated++, needWrite = true;
|
|
92
81
|
}
|
|
93
82
|
|
|
94
83
|
if (needWrite) {
|
|
95
84
|
writeIfChanged(buildPkgPath, JSON.stringify(buildPkg, null, 2) + '\n');
|
|
96
|
-
if (depsUpdated > 0)
|
|
97
|
-
console.log(' ✓ 已同步 ' + depsUpdated + ' 个依赖版本到 ' + BUILD_DIR_NAME + '/package.json');
|
|
98
|
-
}
|
|
85
|
+
if (depsUpdated > 0) console.log(' ✓ 已同步 ' + depsUpdated + ' 个依赖版本到 ' + BUILD_DIR_NAME + '/package.json');
|
|
99
86
|
}
|
|
100
87
|
|
|
101
88
|
if (missing.length > 0) {
|
|
@@ -245,10 +232,8 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
245
232
|
const buildPkgPath = path.join(buildDir, 'package.json');
|
|
246
233
|
if (!fs.existsSync(buildPkgPath)) return console.warn(' ⚠️ 未找到 buildDir/package.json,跳过 extraRnDependencies');
|
|
247
234
|
|
|
248
|
-
const buildPkg = readJson(buildPkgPath);
|
|
235
|
+
const buildPkg = readJson(buildPkgPath), missing = [];
|
|
249
236
|
if (!buildPkg.dependencies) buildPkg.dependencies = {};
|
|
250
|
-
|
|
251
|
-
const missing = [];
|
|
252
237
|
let added = 0;
|
|
253
238
|
for (const name of extras) {
|
|
254
239
|
const pkgJson = path.join(userProjectDir, 'node_modules', name, 'package.json');
|
package/src/fingerprint.js
CHANGED
|
@@ -21,6 +21,26 @@ const FINGERPRINT_FILE = '.build-fingerprint.json',
|
|
|
21
21
|
removeDir(path.join(buildDir, 'android', 'app', 'build'));
|
|
22
22
|
removeDir(path.join(userProjectDir, 'node_modules', '@flun', 'nodejs-mobile-react-native', 'android', 'build'));
|
|
23
23
|
},
|
|
24
|
+
hashTemplate = templateDir => {
|
|
25
|
+
const h = crypto.createHash('sha256'),
|
|
26
|
+
walk = d => {
|
|
27
|
+
let entries;
|
|
28
|
+
try { entries = fs.readdirSync(d, { withFileTypes: true }); } catch { return; }
|
|
29
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
30
|
+
for (const e of entries) {
|
|
31
|
+
if (e.name === 'node_modules' || e.name === '.git') continue;
|
|
32
|
+
const full = path.join(d, e.name), rel = path.relative(templateDir, full).replace(/\\/g, '/');
|
|
33
|
+
if (e.isDirectory()) { h.update('D:' + rel + '|'); walk(full); }
|
|
34
|
+
else if (e.isFile()) {
|
|
35
|
+
h.update('F:' + rel + '|');
|
|
36
|
+
try { h.update(fs.readFileSync(full)); } catch { h.update('err'); }
|
|
37
|
+
h.update('|');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
walk(templateDir);
|
|
42
|
+
return h.digest('hex');
|
|
43
|
+
},
|
|
24
44
|
computeFingerprint = (userProjectDir, config, pkgRoot) => {
|
|
25
45
|
const abiFilters = [...(config.android.abiFilters || [])].sort(), libnode = {},
|
|
26
46
|
pluginDir = path.join(userProjectDir, 'node_modules', '@flun', 'nodejs-mobile-react-native'),
|
|
@@ -36,12 +56,9 @@ const FINGERPRINT_FILE = '.build-fingerprint.json',
|
|
|
36
56
|
}
|
|
37
57
|
}
|
|
38
58
|
|
|
39
|
-
let pluginVersion = null;
|
|
40
|
-
const pluginPkg = path.join(pluginDir, 'package.json');
|
|
59
|
+
let pluginVersion = null, cliVersion = null;
|
|
60
|
+
const pluginPkg = path.join(pluginDir, 'package.json'), cliPkg = path.join(pkgRoot, 'package.json');
|
|
41
61
|
if (fs.existsSync(pluginPkg)) try { pluginVersion = JSON.parse(fs.readFileSync(pluginPkg, 'utf-8')).version; } catch { };
|
|
42
|
-
|
|
43
|
-
let cliVersion = null;
|
|
44
|
-
const cliPkg = path.join(pkgRoot, 'package.json');
|
|
45
62
|
if (fs.existsSync(cliPkg)) try { cliVersion = JSON.parse(fs.readFileSync(cliPkg, 'utf-8')).version; } catch { };
|
|
46
63
|
|
|
47
64
|
const depsHash = hashUserDeps(userProjectDir), a = config.android || {},
|
|
@@ -58,7 +75,8 @@ const FINGERPRINT_FILE = '.build-fingerprint.json',
|
|
|
58
75
|
permissions: [...(a.permissions || [])].sort(),
|
|
59
76
|
};
|
|
60
77
|
|
|
61
|
-
|
|
78
|
+
const templateHash = hashTemplate(path.join(pkgRoot, 'template'));
|
|
79
|
+
return { abiFilters, libnode, pluginVersion, cliVersion, depsHash, appInfo, templateHash };
|
|
62
80
|
},
|
|
63
81
|
checkAndResetCache = (buildDir, userProjectDir, config, pkgRoot) => {
|
|
64
82
|
ensureDir(buildDir);
|
|
@@ -66,14 +84,15 @@ const FINGERPRINT_FILE = '.build-fingerprint.json',
|
|
|
66
84
|
const fpFile = path.join(buildDir, FINGERPRINT_FILE), newFp = computeFingerprint(userProjectDir, config, pkgRoot);
|
|
67
85
|
let oldFp = null;
|
|
68
86
|
if (fs.existsSync(fpFile)) try { oldFp = JSON.parse(fs.readFileSync(fpFile, 'utf-8')); } catch { };
|
|
69
|
-
if (!oldFp) return console.log(' ✓
|
|
87
|
+
if (!oldFp) return console.log(' ✓ 全新构建,无缓存可清'), writeFp(fpFile, newFp);
|
|
70
88
|
|
|
71
89
|
const abiChanged = JSON.stringify(oldFp.abiFilters) !== JSON.stringify(newFp.abiFilters),
|
|
72
90
|
libnodeChanged = JSON.stringify(oldFp.libnode) !== JSON.stringify(newFp.libnode),
|
|
73
91
|
pluginChanged = oldFp.pluginVersion !== newFp.pluginVersion,
|
|
74
92
|
cliChanged = oldFp.cliVersion !== newFp.cliVersion, depsChanged = oldFp.depsHash !== newFp.depsHash,
|
|
75
93
|
appInfoChanged = JSON.stringify(oldFp.appInfo) !== JSON.stringify(newFp.appInfo),
|
|
76
|
-
|
|
94
|
+
templateChanged = oldFp.templateHash !== newFp.templateHash,
|
|
95
|
+
structural = abiChanged || libnodeChanged || pluginChanged || cliChanged || templateChanged;
|
|
77
96
|
|
|
78
97
|
if (structural) {
|
|
79
98
|
const reasons = [];
|
|
@@ -81,6 +100,7 @@ const FINGERPRINT_FILE = '.build-fingerprint.json',
|
|
|
81
100
|
if (libnodeChanged) reasons.push('libnode.so');
|
|
82
101
|
if (pluginChanged) reasons.push('插件版本');
|
|
83
102
|
if (cliChanged) reasons.push('CLI 版本');
|
|
103
|
+
if (templateChanged) reasons.push('模板文件');
|
|
84
104
|
if (depsChanged) reasons.push('用户依赖');
|
|
85
105
|
if (appInfoChanged) reasons.push('应用信息');
|
|
86
106
|
console.log(' ⚠️ 检测到变化(' + reasons.join('、') + '),清理全部缓存');
|
package/src/install.js
CHANGED
|
@@ -1,53 +1,47 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
-
import crypto from 'crypto';
|
|
4
3
|
import { run } from './utils.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
},
|
|
4
|
+
import { optimizeNodeModules, clearVerified, SELF_HASH } from './optimize-node-modules.js';
|
|
5
|
+
const
|
|
6
|
+
/**
|
|
7
|
+
* 内部:从 libnode 的 node_version.h 读取运行时 Node 主版本号
|
|
8
|
+
* 读不到直接报错退出(说明 libnode 目录不完整,继续执行必失败)
|
|
9
|
+
*/
|
|
10
|
+
resolveRuntimeMajor = (userProjectDir, targetPlatform) => {
|
|
11
|
+
const sub = targetPlatform === 'ios' ? 'ios' : 'android',
|
|
12
|
+
header = path.join(userProjectDir, 'node_modules', '@flun', 'nodejs-mobile-react-native',
|
|
13
|
+
sub, 'libnode', 'include', 'node', 'node_version.h');
|
|
14
|
+
if (!fs.existsSync(header)) {
|
|
15
|
+
console.error(' [错误] 未找到 node_version.h: ' + header);
|
|
16
|
+
console.error(' 说明 libnode 目录不完整,请重新安装依赖。'), process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const m = fs.readFileSync(header, 'utf-8').match(/#define\s+NODE_MAJOR_VERSION\s+(\d+)/);
|
|
19
|
+
if (!m) console.error(' [错误] 无法解析 node_version.h 中的 NODE_MAJOR_VERSION'), process.exit(1);
|
|
20
|
+
return m[1];
|
|
21
|
+
},
|
|
24
22
|
/**
|
|
25
23
|
* 内部:判断用户项目的生产依赖里是否含原生模块(binding.gyp)
|
|
26
24
|
* 按用户根 package.json 的 dependencies 键名,去 userProjectDir/node_modules 下逐个查
|
|
27
|
-
* 不用扫 nodejs-project/node_modules
|
|
25
|
+
* 不用扫 nodejs-project/node_modules:全新构建时它还不存在
|
|
28
26
|
*/
|
|
29
|
-
hasNativeModules =
|
|
27
|
+
hasNativeModules = userProjectDir => {
|
|
30
28
|
const pkgPath = path.join(userProjectDir, 'package.json');
|
|
31
29
|
if (!fs.existsSync(pkgPath)) return false;
|
|
32
30
|
let deps = {};
|
|
33
31
|
try {
|
|
34
32
|
deps = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).dependencies || {};
|
|
35
|
-
} catch {
|
|
36
|
-
|
|
37
|
-
}
|
|
33
|
+
} catch { return false; }
|
|
34
|
+
|
|
38
35
|
const nodeModulesDir = path.join(userProjectDir, 'node_modules');
|
|
39
|
-
for (const name of Object.keys(deps))
|
|
36
|
+
for (const name of Object.keys(deps))
|
|
40
37
|
if (fs.existsSync(path.join(nodeModulesDir, name, 'binding.gyp'))) return true;
|
|
41
|
-
}
|
|
42
38
|
return false;
|
|
43
39
|
},
|
|
44
40
|
/**
|
|
45
41
|
* 内部:定位 @flun/nodejs-mobile-react-native 插件目录
|
|
46
42
|
*/
|
|
47
43
|
findPluginDir = userProjectDir => {
|
|
48
|
-
const candidates = [
|
|
49
|
-
path.join(userProjectDir, 'node_modules', '@flun', 'nodejs-mobile-react-native'),
|
|
50
|
-
];
|
|
44
|
+
const candidates = [path.join(userProjectDir, 'node_modules', '@flun', 'nodejs-mobile-react-native')];
|
|
51
45
|
for (const c of candidates) if (fs.existsSync(path.join(c, 'android', 'build.gradle'))) return c;
|
|
52
46
|
return null;
|
|
53
47
|
},
|
|
@@ -55,9 +49,7 @@ const hashDeps = (pkgPath, hasNative, forceRebuild) => {
|
|
|
55
49
|
* 内部:iOS 的 WebView SSL 补丁
|
|
56
50
|
*/
|
|
57
51
|
patchWebViewSslIos = userProjectDir => {
|
|
58
|
-
const file = path.join(
|
|
59
|
-
userProjectDir, 'node_modules', 'react-native-webview', 'apple', 'RNCWebViewImpl.m'
|
|
60
|
-
);
|
|
52
|
+
const file = path.join(userProjectDir, 'node_modules', 'react-native-webview', 'apple', 'RNCWebViewImpl.m');
|
|
61
53
|
if (!fs.existsSync(file)) return;
|
|
62
54
|
|
|
63
55
|
let c = fs.readFileSync(file, 'utf-8');
|
|
@@ -85,29 +77,81 @@ const hashDeps = (pkgPath, hasNative, forceRebuild) => {
|
|
|
85
77
|
/**
|
|
86
78
|
* 装用户项目的生产依赖到 <buildDir>/nodejs-assets/nodejs-project/
|
|
87
79
|
* 只装 dependencies,不装 devDependencies
|
|
88
|
-
*
|
|
80
|
+
* 依赖 + 环境未变化且上次构建完成时跳过;否则按需重装 / 仅优化
|
|
81
|
+
* 快照记录在 buildDir/.deps-snapshot.json(与桌面版一致)
|
|
89
82
|
*/
|
|
90
|
-
installUserDeps = (targetDir, userProjectDir, config) => {
|
|
83
|
+
installUserDeps = async (targetDir, userProjectDir, config, buildDir, targetPlatform) => {
|
|
91
84
|
const assetsDir = path.dirname(targetDir), bnmFile = path.join(assetsDir, 'BUILD_NATIVE_MODULES.txt'),
|
|
92
|
-
|
|
93
|
-
forceRebuild = process.env.NODE_MOBILE_FORCE_REBUILD === '1', hasNative = hasNativeModules(userProjectDir)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
nodeModulesDir = path.join(targetDir, 'node_modules'), snapshotPath = path.join(buildDir, '.deps-snapshot.json'),
|
|
86
|
+
forceRebuild = process.env.NODE_MOBILE_FORCE_REBUILD === '1', hasNative = hasNativeModules(userProjectDir),
|
|
87
|
+
optimizeCfg = config.optimize || {}, thisOptimize = optimizeCfg.enabled !== false,
|
|
88
|
+
abiFilters = [...(config.android.abiFilters || [])].sort(),
|
|
89
|
+
runtimeMajor = resolveRuntimeMajor(userProjectDir, targetPlatform);
|
|
90
|
+
|
|
91
|
+
fs.writeFileSync(bnmFile, hasNative ? '1' : '0');
|
|
92
|
+
if (hasNative) console.log(' ℹ️ 检测到原生模块(binding.gyp),将编译原生代码');
|
|
93
|
+
|
|
94
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(targetDir, 'package.json'), 'utf-8')), deps = pkg.dependencies || {},
|
|
95
|
+
sortedDeps = Object.keys(deps).sort().reduce((acc, k) => { acc[k] = deps[k]; return acc; }, {}),
|
|
96
|
+
snapshotData = { deps: sortedDeps, type: pkg.type || '', hasNative, forceRebuild };
|
|
97
|
+
|
|
98
|
+
let shouldInstall = true, shouldOptimize = thisOptimize, reasons = [];
|
|
99
|
+
if (fs.existsSync(snapshotPath)) {
|
|
100
|
+
const old = JSON.parse(fs.readFileSync(snapshotPath, 'utf-8')), verifiedOk = old.verified === true,
|
|
101
|
+
depsSame = JSON.stringify({
|
|
102
|
+
deps: old.deps, type: old.type, hasNative: old.hasNative, forceRebuild: old.forceRebuild
|
|
103
|
+
}) === JSON.stringify(snapshotData),
|
|
104
|
+
envSame = old.platform === targetPlatform && JSON.stringify(old.abiFilters) === JSON.stringify(abiFilters) &&
|
|
105
|
+
old.runtimeMajor === runtimeMajor,
|
|
106
|
+
lastOptimized = old.optimized !== false, selfHashSame = old.optimizeHash === SELF_HASH,
|
|
107
|
+
nmExists = fs.existsSync(nodeModulesDir);
|
|
108
|
+
if (!depsSame) reasons.push('依赖清单已变化');
|
|
109
|
+
if (!verifiedOk) reasons.push('上次构建未完成');
|
|
110
|
+
if (!envSame) reasons.push('运行环境已变化');
|
|
111
|
+
if (!nmExists) reasons.push('缓存目录缺失');
|
|
112
|
+
if (lastOptimized && !thisOptimize) reasons.push('优化已由开启转为关闭');
|
|
113
|
+
if (thisOptimize && !selfHashSame && lastOptimized) reasons.push('优化程序已更新');
|
|
114
|
+
if (reasons.length > 0) {
|
|
115
|
+
shouldInstall = true, shouldOptimize = thisOptimize;
|
|
116
|
+
console.log(' ℹ️ 需要重新安装依赖(原因: ' + reasons.join(', ') + ')');
|
|
117
|
+
}
|
|
118
|
+
else if (thisOptimize && !lastOptimized)
|
|
119
|
+
shouldInstall = false, shouldOptimize = true, console.log(' ℹ️ 依赖与环境未变化,仅需优化');
|
|
120
|
+
else {
|
|
121
|
+
shouldInstall = false, shouldOptimize = false, console.log(' ✓ 依赖与环境未变化,跳过安装与优化');
|
|
122
|
+
await clearVerified(buildDir);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
} else console.log(' ℹ️ 需要重新安装依赖(原因: 缓存快照缺失)');
|
|
126
|
+
|
|
127
|
+
if (shouldInstall) {
|
|
128
|
+
if (fs.existsSync(nodeModulesDir))
|
|
129
|
+
console.log(' 清理旧 node_modules...'), fs.rmSync(nodeModulesDir, { recursive: true, force: true });
|
|
130
|
+
|
|
131
|
+
try { fs.rmSync(snapshotPath, { force: true }); } catch { }
|
|
132
|
+
const env = { ...process.env };
|
|
133
|
+
if (hasNative) env.NODEJS_MOBILE_BUILD_NATIVE_MODULES = '1';
|
|
134
|
+
console.log(' 安装用户生产依赖(nodejs-assets/nodejs-project)...');
|
|
135
|
+
run('npm', ['install', '--omit=dev', '--no-audit', '--no-fund'], { cwd: targetDir, env, inherit: true });
|
|
136
|
+
const snap = {
|
|
137
|
+
...snapshotData, platform: targetPlatform, abiFilters, runtimeMajor,
|
|
138
|
+
optimizeHash: SELF_HASH, optimized: false, verified: false
|
|
139
|
+
};
|
|
140
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(snap, null, 2));
|
|
141
|
+
console.log(' ✓ 用户依赖安装完成');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (shouldOptimize) {
|
|
145
|
+
try {
|
|
146
|
+
await optimizeNodeModules(targetDir, {
|
|
147
|
+
targetPlatform, abiFilters, runtimeMajor, exclude: optimizeCfg.exclude || [], snapshotDir: buildDir
|
|
148
|
+
});
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.error(' [错误] node_modules 优化失败:' + err.message);
|
|
151
|
+
console.error(' [提示] 可在 mobileAppConfig.js 中设置 optimize: { enabled: false } 关闭优化,');
|
|
152
|
+
console.error(' 或用 optimize: { exclude: ["包名"] } 排除问题包。'), process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
111
155
|
},
|
|
112
156
|
/**
|
|
113
157
|
* 修改 @flun/nodejs-mobile-react-native 插件 build.gradle 的 abiFilters
|
|
@@ -151,7 +195,8 @@ const hashDeps = (pkgPath, hasNative, forceRebuild) => {
|
|
|
151
195
|
if (cancelIndex !== -1) {
|
|
152
196
|
const newCode = [
|
|
153
197
|
'// LOCALHOST_SSL_BYPASS: 对 localhost/127.0.0.1 放行自签名证书(仅本地测试用)',
|
|
154
|
-
' if (failingUrl != null
|
|
198
|
+
' if (failingUrl != null',
|
|
199
|
+
' && (failingUrl.startsWith("https://127.0.0.1") || failingUrl.startsWith("https://localhost"))) {',
|
|
155
200
|
' handler.proceed();',
|
|
156
201
|
' return;',
|
|
157
202
|
' }',
|