You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ship a single-tap Android APK that bundles JSS for non-technical users. Realizes part of #46 ("Solid Pod on Every Phone").
History: original framing was Flutter; pivoted to native Kotlin after research showed there's no maintained Flutter↔nodejs-mobile plugin, and that the plugin layer is unnecessary for a WebView-shell architecture. Decision rationale in this comment.
Architecture
Native Android Studio project (Kotlin), single MainActivity
libnode.so linked directly via JNI/CMake — vendored from nodejs-mobile/nodejs-mobile releases
~80 lines of C++ (JNI shim + stdout/stderr → logcat)
Foreground service wrapping the Node thread (persistent notification)
WebView pointed at http://127.0.0.1:4443/
JSS bundled as APK assets (full node_modules/, copied to Context.filesDir on first launch — ~62 MB tree per scripts/bundle-jss.sh)
Repo scaffolded with README + ARCHITECTURE + LICENSE
scripts/bundle-jss.sh — pulls JSS from npm, installs prod deps, refuses to bundle native modules
Launch args verified end-to-end on dev box: bin/jss.js start --single-user --port 4443 --host 127.0.0.1 --root <files-dir>/data --idp
Android Studio Kotlin project bones (gradle, manifest, MainActivity, theme)
scripts/fetch-libnode.sh — pulls libnode.so for arm64-v8a + armeabi-v7a from nodejs-mobile releases
JNI shim (native-lib.cpp, ~80 LOC, lifted from JaneaSystems samples)
Foreground service + persistent notification ("JSS pod running")
WebView wired to http://127.0.0.1:4443/, with port-bind retry (4443 → 4444 → ...)
First-launch asset copy from APK assets to Context.filesDir
AAB build with ABI splits (arm64-v8a, armeabi-v7a)
Documented v1 caveat: --git, --terminal disabled (both shell out via child_process, not supported by nodejs-mobile)
v1 caveats
No --git, no --terminal — nodejs-mobile's sandboxed Node disallows child_process.
Loopback only by default (HTTP, not HTTPS). Public exposure path is --tunnel against a remote JSS.
Node 18.20.4 is the upstream mobile build (Node 18 EOL'd April 2025). 127.0.0.1 bind cuts the attack surface materially; long-term watch for a community Node 20/22 mobile build.
APK size: libnode is ~30 MB/ABI. Ship as AAB so Play Store delivers per-device.
Out of scope (v1)
iOS — App Store rule 2.5.2 grey zone on dynamic JS eval; needs separate audit.
postmarketOS / Linux ARM64 — later.
A native (Compose/Views) UI replacing the WebView — v2.
Ship a single-tap Android APK that bundles JSS for non-technical users. Realizes part of #46 ("Solid Pod on Every Phone").
Architecture
MainActivitylibnode.solinked directly via JNI/CMake — vendored fromnodejs-mobile/nodejs-mobilereleasesWebViewpointed athttp://127.0.0.1:4443/node_modules/, copied toContext.filesDiron first launch — ~62 MB tree perscripts/bundle-jss.sh)Repo
https://github.com/JavaScriptSolidServer/jss-android (default branch:
gh-pages)v1 scope (Android only)
scripts/bundle-jss.sh— pulls JSS from npm, installs prod deps, refuses to bundle native modulesbin/jss.js start --single-user --port 4443 --host 127.0.0.1 --root <files-dir>/data --idpscripts/fetch-libnode.sh— pullslibnode.sofor arm64-v8a + armeabi-v7a from nodejs-mobile releasesnative-lib.cpp, ~80 LOC, lifted from JaneaSystems samples)http://127.0.0.1:4443/, with port-bind retry (4443 → 4444 → ...)Context.filesDir--git,--terminaldisabled (both shell out viachild_process, not supported by nodejs-mobile)v1 caveats
--git, no--terminal—nodejs-mobile's sandboxed Node disallowschild_process.--tunnelagainst a remote JSS.Out of scope (v1)
Prior art for this pattern
Refs
--tunnelfeature (decentralized ngrok for public exposure)nodejs-mobile— patched Node runtime for Android/iOSnodejs-mobile-samples— reference Kotlin Android project