feat(android): Phase 4 — Rust core to Android .so via JNI
Implement the shared-Rust-core leg of the Android Stage-1 prototype
(docs/superpowers/specs/2026-06-27-android-stage1-prototype-plan.md).
android/rust/catacomb_core is a cdylib that reuses the pure desktop
modules (vtt, error_class, platform) verbatim via #[path] includes — no
logic fork — and exposes them to Kotlin over JNI as String-in/String-out
entry points:
RustCore.vttParse(vtt) -> JSON [{start,text},...]
RustCore.classifyError(log) -> JSON {class,label,hint}
RustCore.platformFromUrl(url) -> JSON {dir_name,display_name,icon}
RustCore.platformDirName(url) -> folder name
Built with panic=abort + per-entry catch_unwind so a Rust panic can never
unwind into the JVM. build.sh locates the NDK portably and cross-compiles
to arm64-v8a + x86_64, depositing the .so into app/src/main/jniLibs/.
Verified: cargo test (38 pass), llvm-readelf confirms all 4 JNI symbols
exported in the arm64 .so, and an end-to-end host-JVM round-trip
(System.load + call each native method) returns correct JSON.
Phases 2/3/5 (WebView-BotGuard anti-bot) remain device-only and untouched.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
f3e6d3b5b7
commit
9a613239f2
7 changed files with 796 additions and 0 deletions
40
android/rust/catacomb_core/Cargo.toml
Normal file
40
android/rust/catacomb_core/Cargo.toml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Android JNI core for Catacomb (Stage-1 prototype, Phase 4).
|
||||
#
|
||||
# A thin cdylib that reuses Catacomb's *pure* modules (vtt, error_class,
|
||||
# platform) verbatim via `#[path]` includes so the on-device engine stays in
|
||||
# lockstep with the desktop/web build instead of forking the logic. It exposes
|
||||
# a handful of String-in / String-out JNI entry points the Kotlin layer calls.
|
||||
#
|
||||
# The empty `[workspace]` table isolates this crate from the desktop package
|
||||
# that lives at the repository root (which is a plain package, not a
|
||||
# workspace); without it cargo would try to treat the two as one workspace.
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "catacomb_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-only"
|
||||
description = "Android JNI bridge exposing Catacomb's pure Rust modules on-device."
|
||||
|
||||
[lib]
|
||||
# cdylib → a .so loadable by the JVM via System.loadLibrary("catacomb_core").
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# Same major as the desktop crate so the shared modules' derives resolve
|
||||
# identically.
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
# JNI bindings. 0.21 is the current stable line and links against the JVM's
|
||||
# built-in libjvm at runtime (no extra native dep on device).
|
||||
jni = "0.21"
|
||||
|
||||
[profile.release]
|
||||
# Small, fast .so: LTO + panic=abort (a Rust panic must never unwind across
|
||||
# the FFI boundary into the JVM — that's UB; abort is the safe choice, and we
|
||||
# also catch panics at each entry point as defense in depth).
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
panic = "abort"
|
||||
strip = true
|
||||
Loading…
Add table
Add a link
Reference in a new issue