feat(mobile): Node 18.20.4 embedded runtime + cordova-bridge fix (batch 6/6.5)
Swap the abandoned nodejs-mobile Node 12.19 runtime for the nodejs-mobile core Node 18.20.4 Android build, staged into the plugin by install-node18-runtime.sh (the cordova fork's Android side is still Node 12). Re-register the cordova-bridge linked binding via explicit napi_module_register(NM_F_LINKED), since Node 18's NAPI_MODULE_X macro drops the flag and process._linkedBinding could no longer find it. Verified on the x86_64 emulator: process.version=v18.20.4 and a full native<->node channel round-trip (device encryption key delivered). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0c58b7a4a5
commit
3e115dd349
|
|
@ -0,0 +1,115 @@
|
|||
#!/usr/bin/env bash
|
||||
# Batch 6 — swap the embedded runtime to Node 18.20.4.
|
||||
#
|
||||
# The published nodejs-mobile-cordova (0.4.3) and its community fork's `unstable`
|
||||
# branch both still ship Node 12.19.0 for Android. Node 18 for Android exists only
|
||||
# in the nodejs-mobile CORE release (github.com/nodejs-mobile/nodejs-mobile). This
|
||||
# script stages that core runtime into the installed plugin so the existing native
|
||||
# glue (native-lib.cpp calls node::Start, cordova-bridge is N-API) rebuilds against
|
||||
# Node 18 — verified: node::Start, AddLinkedBinding, and the N-API surface are all
|
||||
# present in the v18 libnode, and the SONAME is unchanged (libnode.so).
|
||||
#
|
||||
# node_modules/ is regenerated by `npm install`, so RE-RUN this after any install
|
||||
# (same pattern as fix-better-sqlite3-android.sh). Run from the mobile project root.
|
||||
#
|
||||
# Node 18 core ships arm64-v8a / armeabi-v7a / x86_64 only — there is no 32-bit x86
|
||||
# build, so the plugin's stale v12 x86 libnode is left untouched (x86 should be
|
||||
# dropped from abiFilters + prepare-android-assets.js in Batch 7).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
NODE_MOBILE_VERSION="18.20.4"
|
||||
ZIP_NAME="nodejs-mobile-v${NODE_MOBILE_VERSION}-android.zip"
|
||||
ZIP_URL="https://github.com/nodejs-mobile/nodejs-mobile/releases/download/v${NODE_MOBILE_VERSION}/${ZIP_NAME}"
|
||||
ABIS=(arm64-v8a armeabi-v7a x86_64)
|
||||
|
||||
MOBILE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
PLUGIN_LIBNODE="$MOBILE_DIR/node_modules/nodejs-mobile-cordova/libs/android/libnode"
|
||||
CACHE_DIR="$MOBILE_DIR/build-output/nodejs-mobile-runtime" # gitignored
|
||||
EXTRACT_DIR="$CACHE_DIR/nm18-android"
|
||||
|
||||
if [[ ! -d "$PLUGIN_LIBNODE" ]]; then
|
||||
echo "Error: nodejs-mobile-cordova not installed at $PLUGIN_LIBNODE" >&2
|
||||
echo "Run 'npm install' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
# 1. Fetch the core Android runtime (cached).
|
||||
if [[ ! -f "$CACHE_DIR/$ZIP_NAME" ]]; then
|
||||
echo "Downloading $ZIP_NAME (~57 MB)…"
|
||||
curl -fL --retry 3 -o "$CACHE_DIR/$ZIP_NAME" "$ZIP_URL"
|
||||
fi
|
||||
|
||||
rm -rf "$EXTRACT_DIR"
|
||||
mkdir -p "$EXTRACT_DIR"
|
||||
unzip -q -o "$CACHE_DIR/$ZIP_NAME" -d "$EXTRACT_DIR"
|
||||
|
||||
# 2. Swap libnode.so per ABI (plugin ships them gzipped; hook gunzips at build time).
|
||||
for abi in "${ABIS[@]}"; do
|
||||
src="$EXTRACT_DIR/bin/$abi/libnode.so"
|
||||
destdir="$PLUGIN_LIBNODE/bin/$abi"
|
||||
if [[ ! -f "$src" ]]; then
|
||||
echo "Error: missing $src in the core archive" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$destdir"
|
||||
gzip -c "$src" > "$destdir/libnode.so.gz"
|
||||
echo " staged libnode.so.gz -> bin/$abi ($(du -h "$destdir/libnode.so.gz" | cut -f1))"
|
||||
done
|
||||
|
||||
# 3. Swap headers (used to compile native-lib.cpp and native modules, e.g.
|
||||
# better-sqlite3 in Batch 8).
|
||||
rm -rf "$PLUGIN_LIBNODE/include/node"
|
||||
mkdir -p "$PLUGIN_LIBNODE/include"
|
||||
cp -R "$EXTRACT_DIR/include/node" "$PLUGIN_LIBNODE/include/node"
|
||||
|
||||
# 3.5 Patch the cordova-bridge linked-binding registration for Node 18.
|
||||
#
|
||||
# Node 18's NAPI_MODULE_X macro drops its priv/flags args and expands to the
|
||||
# symbol-based NAPI_MODULE registration, which Node only consumes when it
|
||||
# dlopen()s a .node file. cordova-bridge is compiled INTO the app's native lib,
|
||||
# so it was never registered and process._linkedBinding('cordova_bridge') failed
|
||||
# with "No such binding was linked". Register the linked binding explicitly via
|
||||
# the still-supported napi_module_register path (routes NM_F_LINKED modules into
|
||||
# the global modlist_linked at static-init, before node::Start). Idempotent.
|
||||
BRIDGE_CPP="$MOBILE_DIR/node_modules/nodejs-mobile-cordova/src/common/cordova-bridge/cordova-bridge.cpp"
|
||||
if [[ -f "$BRIDGE_CPP" ]]; then
|
||||
python3 - "$BRIDGE_CPP" <<'PY'
|
||||
import sys
|
||||
p = sys.argv[1]
|
||||
src = open(p).read()
|
||||
old = "NAPI_MODULE_X(cordova_bridge, Init, NULL, NM_F_LINKED)"
|
||||
new = """static napi_module _cordova_bridge_module = {
|
||||
NAPI_MODULE_VERSION,
|
||||
NM_F_LINKED,
|
||||
__FILE__,
|
||||
Init,
|
||||
"cordova_bridge",
|
||||
NULL,
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
__attribute__((constructor)) static void _register_cordova_bridge(void) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
napi_module_register(&_cordova_bridge_module);
|
||||
#pragma GCC diagnostic pop
|
||||
}"""
|
||||
if "_register_cordova_bridge" in src:
|
||||
print(" cordova-bridge.cpp already patched for Node 18 linked binding")
|
||||
elif old in src:
|
||||
open(p, "w").write(src.replace(old, new))
|
||||
print(" patched cordova-bridge.cpp linked-binding registration for Node 18")
|
||||
else:
|
||||
sys.exit(" ERROR: cordova-bridge.cpp registration line not found — plugin changed?")
|
||||
PY
|
||||
fi
|
||||
|
||||
# 4. Confirm.
|
||||
ver_h="$PLUGIN_LIBNODE/include/node/node_version.h"
|
||||
maj=$(grep -E 'define NODE_MAJOR_VERSION' "$ver_h" | awk '{print $3}')
|
||||
min=$(grep -E 'define NODE_MINOR_VERSION' "$ver_h" | awk '{print $3}')
|
||||
pat=$(grep -E 'define NODE_PATCH_VERSION' "$ver_h" | awk '{print $3}')
|
||||
echo "Done. Plugin libnode headers now report Node ${maj}.${min}.${pat}."
|
||||
echo "Next: rebuild the app (npx cap sync android + gradle) and boot main.js to confirm process.version."
|
||||
Loading…
Reference in New Issue