mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-20 16:29:31 +00:00
Regenerates the wrapper (MyTimerNode.kt) and JNI shim (my_timer_jni.c) via `nimble genbindings_kotlin`, removing the hand-written sources, and points the instrumented test at the derived MyTimerNode class. Validated by cross-compiling both ABIs with the NDK: arm64-v8a + x86_64 build clean, the four Java_org_logos_mytimer_MyTimerNode_* symbols are exported, and libmy_timer_jni.so correctly NEEDS libmy_timer.so. (The Kotlin/Gradle layer still runs on a device/emulator.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Android example — Kotlin over the native C ABI (JNI)
An Android library module that wraps the timer library's native
(zero-serialization) C ABI behind an idiomatic Kotlin class, TimerNode, via a
small JNI shim. Struct returns come back as typed Kotlin values.
TimerNode("my-app").use { node ->
println(node.version()) // "nim-timer v0.1.0"
val r = node.echo("hello", delayMs = 5)
println("${r.echoed} / ${r.timerName}")
}
How it fits together
Kotlin TimerNode ──external fun──▶ libmy_timer_jni.so ──C ABI──▶ libmy_timer.so
(src/main/kotlin) (jni/my_timer_jni.c) (Nim, generated)
libmy_timer.so— the Nim library, exporting the native C ABI.libmy_timer_jni.so— a JNI shim that turns eachnativeKotlin method into a blocking call into that ABI, reading the typedEchoResponsestruct out of the result callback. ItNEEDSlibmy_timer.soat load time.
| Path | Description |
|---|---|
build-libs.sh |
Cross-compiles both .sos per ABI into src/main/jniLibs/<abi>/. |
jni/my_timer_jni.c |
The JNI bridge. |
src/main/kotlin/.../TimerNode.kt |
The Kotlin wrapper + EchoResult. |
build.gradle.kts, settings.gradle.kts |
Library module build files. |
src/androidTest/... |
Instrumented test (runs on a device/emulator). |
Build
cd examples/timer/android
export ANDROID_NDK_ROOT=/path/to/android-ndk # or rely on the default
./build-libs.sh # arm64-v8a + x86_64 by default
This stages libmy_timer.so + libmy_timer_jni.so under src/main/jniLibs/.
The Android Gradle plugin packages everything under jniLibs/ into the AAR/APK
automatically — no extra Gradle config needed.
Add ABIs by extending the table at the bottom of build-libs.sh and the
abiFilters in build.gradle.kts.
Use it
- As a module: drop
android/into your project,include(":mytimer")in yoursettings.gradle, andimplementation(project(":mytimer")). - By hand: copy
src/main/jniLibs/<abi>/*.sointo your app'sjniLibs/andTimerNode.ktinto your sources.
Then org.logos.mytimer.TimerNode is ready to use.
Run the test
./gradlew connectedAndroidTest # needs a connected device or emulator
Notes
- This is the native, same-process path — the app loads the library directly.
The CBOR ABI is for inter-process communication only (see
../ipc). - Each call blocks on a condvar in the JNI shim until the library's FFI-thread callback fires, so the Kotlin API is simple and synchronous.
- Regenerate
../c_bindings/my_timer.hwithnimble genbindings_c(from the repo root) if the library's API changes.