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
51
android/app/src/main/java/com/catacomb/spike/RustCore.kt
Normal file
51
android/app/src/main/java/com/catacomb/spike/RustCore.kt
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package com.catacomb.spike
|
||||
|
||||
/**
|
||||
* Kotlin binding for the Catacomb Rust core (`libcatacomb_core.so`).
|
||||
*
|
||||
* This is the JVM side of the Phase-4 JNI bridge proven in
|
||||
* `android/rust/catacomb_core`. Each `external fun` resolves to a
|
||||
* `#[no_mangle] pub extern "system" fn Java_com_catacomb_spike_RustCore_<name>`
|
||||
* symbol in the shared library, so the method names here **must** match the
|
||||
* Rust exports exactly (verified via `llvm-readelf --dyn-syms`).
|
||||
*
|
||||
* The `.so` must be on the app's `jniLibs` path per ABI, e.g.
|
||||
* `app/src/main/jniLibs/arm64-v8a/libcatacomb_core.so`
|
||||
* (produced by `android/rust/catacomb_core/build.sh`).
|
||||
*
|
||||
* All calls cross into Rust, which reuses the *same* modules the desktop/web
|
||||
* build uses (`vtt`, `error_class`, `platform`) — no logic fork.
|
||||
*/
|
||||
object RustCore {
|
||||
init {
|
||||
// Loads libcatacomb_core.so from the ABI-specific jniLibs folder.
|
||||
System.loadLibrary("catacomb_core")
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse WebVTT/SRT subtitle text into a JSON array of cues:
|
||||
* `[{"start": <seconds:Double>, "text": <String>}, …]`.
|
||||
* Returns `"[]"` for empty/unparseable input.
|
||||
*/
|
||||
external fun vttParse(vtt: String): String
|
||||
|
||||
/**
|
||||
* Classify a yt-dlp failure log (one log entry per line) into JSON:
|
||||
* `{"class": <kebab-id>, "label": <String>, "hint": <String>}`.
|
||||
* `class` is one of: rate-limited, members-only, geo-blocked, not-found,
|
||||
* codec-missing, disk-full, network-error, bad-cookies, other.
|
||||
*/
|
||||
external fun classifyError(log: String): String
|
||||
|
||||
/**
|
||||
* Resolve a media URL to its platform descriptor JSON:
|
||||
* `{"dir_name": <String>, "display_name": <String>, "icon": <String>}`.
|
||||
*/
|
||||
external fun platformFromUrl(url: String): String
|
||||
|
||||
/**
|
||||
* The on-disk backup-folder name for a URL's platform
|
||||
* (e.g. `"channels"` for YouTube, `"tiktok"`, …, `"other"`).
|
||||
*/
|
||||
external fun platformDirName(url: String): String
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue