|
1
|
--- |
|
2
|
name: sdk-kotlin-lib |
|
3
|
description: Build the Onde Kotlin Android library from Rust source using UniFFI bindings. Use when cross-compiling libonde.so for Android ABIs, generating Kotlin bindings, or modifying the build-kotlin.sh pipeline. |
|
4
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash |
|
5
|
user-invocable: false |
|
6
|
--- |
|
7
|
|
|
8
|
# Skill: Onde Kotlin SDK (Android Library) |
|
9
|
|
|
10
|
## What This Skill Covers |
|
11
|
|
|
12
|
Building the `onde` Kotlin Android library from the Rust crate using UniFFI bindings. The output is a Kotlin/JVM library module (`sdk/kotlin/onde/`) with: |
|
13
|
|
|
14
|
- Pre-compiled `.so` native libraries for all four Android ABIs (`arm64-v8a`, `armeabi-v7a`, `x86_64`, `x86`) under `jniLibs/` |
|
15
|
- Auto-generated Kotlin source at `sdk/kotlin/onde/src/main/kotlin/com/ondeinference/onde/onde.kt` |
|
16
|
|
|
17
|
## Crate & Tooling Layout |
|
18
|
|
|
19
|
``` |
|
20
|
onde/ |
|
21
|
├── Cargo.toml # crate-type = ["lib", "cdylib", "staticlib"] |
|
22
|
├── uniffi.toml # [bindings.kotlin] package_name = "com.ondeinference.onde" |
|
23
|
├── build-kotlin.sh # main build script — cross-compiles + runs bindgen |
|
24
|
├── uniffi-bindgen/ |
|
25
|
│ ├── Cargo.toml # bin: uniffi-bindgen, dep: uniffi = "=0.31.0", features = ["cli"] |
|
26
|
│ └── uniffi-bindgen.rs # fn main() { uniffi::uniffi_bindgen_main() } |
|
27
|
└── sdk/kotlin/onde/ |
|
28
|
└── src/main/ |
|
29
|
├── jniLibs/<ABI>/libonde.so |
|
30
|
└── kotlin/com/ondeinference/onde/onde.kt |
|
31
|
``` |
|
32
|
|
|
33
|
## Key Constraints |
|
34
|
|
|
35
|
- **UniFFI is pinned to `=0.31.0`** in both `Cargo.toml` (lib) and `uniffi-bindgen/Cargo.toml`. Never change this independently — both must stay in sync. |
|
36
|
- **`cdylib` crate-type** is required for the `.so` output consumed by the JVM at runtime. |
|
37
|
- **`uniffi::setup_scaffolding!()`** in `src/lib.rs` is the proc-macro approach — no `.udl` file is needed. |
|
38
|
- **Android NDK minimum API = 24** (`MIN_API=24` in `build-kotlin.sh`) to match the library's `minSdk`. |
|
39
|
- **Package name is `com.ondeinference.onde`** — set in `uniffi.toml`, never override in bindgen flags. |
|
40
|
|
|
41
|
## Build Command |
|
42
|
|
|
43
|
```bash |
|
44
|
# Full release build for all four Android ABIs |
|
45
|
./build-kotlin.sh |
|
46
|
|
|
47
|
# Debug build, arm64 only |
|
48
|
./build-kotlin.sh --debug --target aarch64-linux-android |
|
49
|
|
|
50
|
# Regenerate Kotlin source from an existing .so (skip Rust compilation) |
|
51
|
./build-kotlin.sh --generate-only |
|
52
|
``` |
|
53
|
|
|
54
|
The script: |
|
55
|
1. Builds the `onde-uniffi-bindgen` CLI binary (host). |
|
56
|
2. Cross-compiles `libonde.so` for each selected Android target using the NDK clang toolchain. |
|
57
|
3. Copies `.so` files into `sdk/kotlin/onde/src/main/jniLibs/<ABI>/`. |
|
58
|
4. Runs `uniffi-bindgen generate --library <.so> --language kotlin --out-dir <src_root> --config uniffi.toml`. |
|
59
|
|
|
60
|
## NDK Setup |
|
61
|
|
|
62
|
The script auto-detects the NDK in order: |
|
63
|
1. `$ANDROID_NDK_HOME` |
|
64
|
2. `$ANDROID_HOME/ndk/` (picks newest version) |
|
65
|
3. `~/Library/Android/sdk/ndk/` (macOS default) |
|
66
|
4. `~/Android/Sdk/ndk/` (Linux default) |
|
67
|
|
|
68
|
Or pass explicitly: `./build-kotlin.sh --ndk /path/to/ndk` |
|
69
|
|
|
70
|
Required Rust targets: |
|
71
|
```bash |
|
72
|
rustup target add \ |
|
73
|
aarch64-linux-android \ |
|
74
|
armv7-linux-androideabi \ |
|
75
|
x86_64-linux-android \ |
|
76
|
i686-linux-android |
|
77
|
``` |
|
78
|
|
|
79
|
## UniFFI Binding Rules |
|
80
|
|
|
81
|
All types that cross the FFI boundary must carry the appropriate UniFFI derive: |
|
82
|
|
|
83
|
| Rust trait/derive | Kotlin output | |
|
84
|
|---------------------------|---------------------------| |
|
85
|
| `#[derive(uniffi::Record)]` | `data class` | |
|
86
|
| `#[derive(uniffi::Enum)]` | `sealed class` / `enum` | |
|
87
|
| `#[derive(uniffi::Error)]` | `sealed class` (throwable)| |
|
88
|
| `#[derive(uniffi::Object)]` | `class` (Arc-backed) | |
|
89
|
| `#[uniffi::export(callback_interface)]` | `interface` | |
|
90
|
|
|
91
|
**Forbidden in UniFFI-exported types:** |
|
92
|
- `usize` / `isize` — use `u64` / `i64` instead |
|
93
|
- `impl Into<String>` — use concrete `String` |
|
94
|
- `tokio::sync::mpsc::Receiver` — use `callback_interface` + free function |
|
95
|
- Callback interfaces as parameters of `#[derive(uniffi::Object)]` methods — must be free functions |
|
96
|
|
|
97
|
## Adding a New Exported Function or Type |
|
98
|
|
|
99
|
1. Add the type/function in the relevant `src/` file with the correct UniFFI derive or `#[uniffi::export]`. |
|
100
|
2. Verify `uniffi::setup_scaffolding!()` is still the only scaffolding call in `src/lib.rs`. |
|
101
|
3. Re-run `./build-kotlin.sh --generate-only` (if a compiled `.so` already exists) or the full build. |
|
102
|
4. The new class/function will appear in `sdk/kotlin/onde/src/main/kotlin/com/ondeinference/onde/onde.kt`. |
|
103
|
5. Never hand-edit `onde.kt` — it is always fully regenerated. |
|
104
|
|
|
105
|
## Common Pitfalls |
|
106
|
|
|
107
|
- **Version mismatch between `uniffi` in `Cargo.toml` and `uniffi-bindgen/Cargo.toml`** — bindgen will refuse to process the library and emit a schema version error. Both must be `=0.31.0`. |
|
108
|
- **Missing `cdylib` in `crate-type`** — `cargo build` will not produce a `.so`. The `Cargo.toml` must keep `["lib", "cdylib", "staticlib"]`. |
|
109
|
- **`___chkstk_darwin` linker error** — only occurs on tvOS, not Android. Ignore on Android builds. |
|
110
|
- **Android sandbox has no `HOME`** — `dirs::home_dir()` returns `None` inside the Android sandbox. On Android, `hf-hub` is a direct dependency (not optional) so that the HF cache path can be set explicitly via `GLOBAL_HF_CACHE` before any model download. |
|
111
|
- **`libonde.so` not found after build** — the script searches multiple candidate paths including workspace `target/`. If the workspace `target/` is above the crate directory, the fallback path logic in `build-kotlin.sh` will find it. |