Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Node Bridge

English · 中文

Embed a real Node.js runtime inside your mobile app's own process — not a WebView, not a cloud function, not a subprocess, not a shipped binary. A JNI/NAPI bootstrap calls dlopen("libnode.so") + node::Start in-process, with a bidirectional JSON bridge between JavaScript and the host language (Kotlin on Android, ArkTS on HarmonyOS).

This workspace is the umbrella for five repositories — on each platform the work is split into two independently published packages: a bridge (API + loader, its own semver) and a runtime (the engine binary, versioned exactly like Node.js). Android also ships a companion node-pty addon, versioned with the engine. A project website sits alongside them.

The five repositories

Repository Platform / registry Package Ships
aosp-node-bridge Android · Maven Central io.github.fellow99:node-bridge:0.2.0 Kotlin API, JNI bootstrap (libnode_bridge.so), NAPI addon (libnode_host_client.so), JS payload
aosp-node-runtime Android · Maven Central io.github.fellow99:node-runtime:24.22.1 libnode.so + libc++_shared.so only — engine version equals the Node.js version
aosp-node-pty Android · GitHub Release (Maven pending) io.github.fellow99:node-pty:24.22.1 libpty_node.so only — cross-compiled node-pty addon, DT_NEEDED libnode.so; paired 1:1 with the runtime
ohos-node-bridge HarmonyOS · ohpm @fellow99/node-bridge@0.2.0 ArkTS API + type declarations, NAPI bootstrap .so, crash forensics
ohos-node-runtime HarmonyOS · ohpm @fellow99/node-runtime@24.2.0 libnode.so (arm64-v8a) + libc++_shared.so, Node.js LICENSE, version constants
node-bridge-website — — Project website (EN/中文, light/dark)

Engine: Android Node.js v24.22.1 · HarmonyOS Node.js v24.2.0 · ABI arm64-v8a · Android minSdk 24 · HarmonyOS 2in1 / tablet (no phone). The node-pty addon is version-for-version with the Android runtime (NODE_MODULE_VERSION 137).

Why two packages

The bridge and the engine are coupled by a runtime symbol contract, not a compile-time link:

  • libnode_bridge.so links only log/dl — it never links libnode. It finds the engine with dlopen and node::Start with dlsym, so the bridge is decoupled from the Node version.
  • The NAPI addon leaves its napi_* symbols undefined on purpose and resolves them at runtime against the already-loaded libnode.so (RTLD_GLOBAL), guaranteeing Node's own N-API is used.
  • The only symbols the bridge depends on are _ZN4node5StartEiPPc (node::Start(int, char**)) and the stable N-API surface — swapping Node versions needs no bridge recompile.
┌──────────────────────────── App process ────────────────────────────┐
│                                                                     │
│   Kotlin / ArkTS   NodeRuntime · HostBridge                         │
│        ▲  result (JSON)              │ host requests (JSON)         │
│        ▼                              ▼                             │
│   libnode_bridge.so  ◀─ slot table ─▶ libnode_host_client.so (NAPI) │
│        ▲ dlopen + dlsym                   ▲ process.dlopen          │
│        └────────────┐        ┌───────────┘                          │
│                 libnode.so (Node.js + V8)  ◀── bootstrap/host.js    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

The engine binary is never committed and never built by hand: cloud CI cross-compiles it from the official Node.js tarball, asserts it is ET_DYN, has no PT_INTERP and exports node::Start, then publishes it. runtime.lock.json is the single source of truth for version, SHA-256, ELF gates and provenance.

Quick start

Android (Maven Central)

// build.gradle.kts
dependencies {
    implementation("io.github.fellow99:node-bridge:0.2.0")
    runtimeOnly("io.github.fellow99:node-runtime:24.22.1") // engine, pinned to Node
    // optional: cross-compiled node-pty addon, same version as the runtime (GitHub Release today)
    runtimeOnly("io.github.fellow99:node-pty:24.22.1")
}
// Register host capabilities FIRST, then start (order matters).
val rt = NodeRuntime.getInstance(context)
rt.host.register("fs.pickFolder") { """{"ok":true,"path":"/sdcard/Download"}""" }
rt.start(NodeRuntimeOptions(entry = "bootstrap.js", appEntry = "selfcheck.js"))
rt.state.collect { state -> /* Idle → Starting → Running → Exited/Failed */ }

HarmonyOS (ohpm)

ohpm install @fellow99/node-bridge
ohpm install @fellow99/node-runtime@24.2.0
import { NodeRuntime } from '@fellow99/node-bridge';
NodeRuntime.getInstance().start(ctx, { scriptPath: '<sandbox>/payload/bootstrap.js' });

V8 JIT additionally requires the ohos.permission.kernel.ALLOW_WRITABLE_CODE_MEMORY ACL declared in your module.json5; --jitless is the fallback (WebAssembly unavailable).

Cloning

All five repositories plus the website are wired in as git submodules:

git clone --recurse-submodules https://github.com/fellow99/node-bridge-workspace.git
# or, after a plain clone:
git submodule update --init --recursive
node-bridge-workspace/
├── aosp-node-bridge/      # Android bridge — Kotlin API + JNI/NAPI bootstrap (Maven)
├── aosp-node-runtime/     # Android engine — cross-compiled libnode.so AAR (Maven)
├── aosp-node-pty/         # Android node-pty addon — cross-compiled libpty_node.so (Release, Maven pending)
├── ohos-node-bridge/      # HarmonyOS bridge — ArkTS API + NAPI bootstrap (ohpm)
├── ohos-node-runtime/     # HarmonyOS engine — libnode.so HAR (ohpm)
└── node-bridge-website/   # Project website — plain HTML/CSS/JS, EN/中文, light/dark

Constraints (reported, never silently degraded)

  • node::Start is once per process — a crash/exit is terminal (Exited/Failed); for a restartable form, run Node in a dedicated :node process.
  • JIT must be verified on device — W^X/execmem rules and HarmonyOS ACLs can block V8 JIT. JIT and WebAssembly are verified working on Android 15 and HarmonyOS 2in1 devices.
  • arm64-v8a only, no other ABIs; HarmonyOS targets 2in1/tablet, not phones.

License

All repositories are MIT. The bundled Node.js engine is covered by the upstream Node.js MIT license (including V8/OpenSSL/ICU third-party notices, shipped with each runtime package).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors