Skip to content

feat(android): add cktap-android Kotlin/Android bindings via UniFFI#69

Merged
reez merged 5 commits intobitcoindevkit:masterfrom
r1b2ns:feat/android-ffi
Apr 15, 2026
Merged

feat(android): add cktap-android Kotlin/Android bindings via UniFFI#69
reez merged 5 commits intobitcoindevkit:masterfrom
r1b2ns:feat/android-ffi

Conversation

@r1b2ns
Copy link
Copy Markdown
Contributor

@r1b2ns r1b2ns commented Apr 15, 2026

Description

Adds the new cktap-android module, which packages the rust-cktap library as a Kotlin/Android .aar consumable from any Android project. The Kotlin API surface is auto-generated from the cktap-ffi crate via uniffi-rs, and the AAR bundles the native libcktap_ffi.so for arm64-v8a, armeabi-v7a, and x86_64.

What's included:

  • cktap-android/ — Gradle Android library project (Kotlin 2.x, JDK 17, Android SDK 34, NDK 27.2.x)
    • lib/build.gradle.ktscom.vanniktech.maven.publish setup with Dokka, sources JAR, and a localBuild property that skips GPG signing for local development
    • scripts/dev/build-dev-macos-aarch64.sh — single-ABI dev build (arm64-v8a) for fast iteration
    • scripts/release/build-release-macos-aarch64.sh — release build across all supported ABIs
    • justfile with recipes: build, build-dev, clean, publish-local, publish-central, docs, test
    • README.md — architecture overview (app → cktap-android → cktap-ffi → rust-cktap), usage, local Maven publish flow, and known issues
  • cktap-ffi/.cargo/config.toml — Android target linker configuration
  • cktap-ffi/uniffi-android.toml / uniffi.toml — UniFFI generator configuration for Android
  • rust-toolchain.toml — pins the toolchain for reproducible native builds

Notes to the reviewers

  • UniFFI: the Kotlin bindings are generated at build time from cktap-ffi — nothing is checked in under lib/src/main/kotlin/com/coinkite/cktap/. The clean just recipe removes the generated files along with build/ and jniLibs/.
  • Local publishing: just publish-local runs ./gradlew publishToMavenLocal -P localBuild. The -P localBuild flag makes signing conditional in lib/build.gradle.kts, so contributors can build the AAR without GPG keys or Sonatype credentials. Maven Central publishing (just publish-central) still requires the usual signing/credential setup.
  • Native build scope: scripts currently target macOS aarch64 hosts. Cross-compiling from other hosts (Linux/Intel Mac) will need additional scripts — left as a follow-up.
  • JNA runtime: cktap-android depends on JNA at runtime (net.java.dev.jna:jna:5.14.0@aar). Consumers whose JVM doesn't expose com.sun.jna.Pointer must add JNA explicitly — documented under "Known issues" in the README.
  • Versioning: published as org.bitcoindevkit:cktap-android:0.1.0-SNAPSHOT pending the first release tag.

Changelog notice

Added cktap-android module: Kotlin/Android language bindings for rust-cktap, generated via UniFFI and packaged as an .aar with prebuilt native libraries for arm64-v8a, armeabi-v7a, and x86_64.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

r1b2ns added 3 commits April 14, 2026 10:30
Sets up a cktap-android Gradle project that mirrors cktap-swift and
follows the bdk-android structure. Cross-compiles libcktap_ffi.so for
arm64-v8a, x86_64 and armeabi-v7a via the Android NDK and generates
Kotlin bindings under the com.coinkite.cktap package.

- Add uniffi.toml, uniffi-android.toml and .cargo/config.toml in
  cktap-ffi/ for Kotlin package name, Android cleaner and 16KB page
  size alignment
- Add Android targets to rust-toolchain.toml
- Add cktap-android Gradle project (AGP 8.13.2, Kotlin 2.3.10,
  compileSdk 34, minSdk 24, JVM 17, JNA 5.14.0)
- Add release (3-arch) and dev (arm64-only) build scripts plus a
  justfile with build/clean/test recipes
@r1b2ns r1b2ns marked this pull request as draft April 15, 2026 16:14
@r1b2ns r1b2ns changed the title feat(android): add cktap-android Kotlin/Android bindings via UniFFI [draft]feat(android): add cktap-android Kotlin/Android bindings via UniFFI Apr 15, 2026
Copy link
Copy Markdown
Collaborator

@reez reez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excited this is in progress!

The Android binding direction looks good, but I wasn't finding the current release flow not reproducible. From a clean checkout, publishToMavenLocal -P localBuild succeeds while publishing an empty AAR, which means publish is packaging whatever happens to be under lib/src/main/kotlin and lib/src/main/jniLibs instead of building the artifact. Also im seeing the advertised full release recipe (just clean && just build macos-aarch64) currently fails at the UniFFI generate step with No UniFFI metadata found for the release-smaller Android .so, so the documented release path must be broken?

Not sure if you've run into these or its just me and I might have done something wrong.

Im assuming you're using these on the SATSBUDDY-android app so that will be nice in checking off "does this work with a real app" part 👍

- Drop `strip = true` from the `release-smaller` profile: uniffi-bindgen
  `--library` mode reads UNIFFI_META_* symbols from the .so, and stripping
  at compile time removed them, breaking the generate step with
  "No UniFFI metadata found".
- Strip the jniLibs copies explicitly with `llvm-strip` after bindings are
  generated so the shipped AAR stays small.
- Add a `verifyFfiArtifacts` Gradle task wired before `preBuild` that fails
  fast when `lib/src/main/kotlin/**/*.kt` or `lib/src/main/jniLibs/**/libcktap_ffi.so`
  are missing, instead of silently publishing an empty AAR.
@r1b2ns
Copy link
Copy Markdown
Contributor Author

r1b2ns commented Apr 15, 2026

Excited this is in progress!

The Android binding direction looks good, but I wasn't finding the current release flow not reproducible. From a clean checkout, publishToMavenLocal -P localBuild succeeds while publishing an empty AAR, which means publish is packaging whatever happens to be under lib/src/main/kotlin and lib/src/main/jniLibs instead of building the artifact. Also im seeing the advertised full release recipe (just clean && just build macos-aarch64) currently fails at the UniFFI generate step with No UniFFI metadata found for the release-smaller Android .so, so the documented release path must be broken?

Not sure if you've run into these or its just me and I might have done something wrong.

Im assuming you're using these on the SATSBUDDY-android app so that will be nice in checking off "does this work with a real app" part 👍

Hi man, I just pushed some fix. Could you try again?

cktap-android $ just clean && just build && just publish-local

@reez

@reez
Copy link
Copy Markdown
Collaborator

reez commented Apr 15, 2026

Excited this is in progress!
The Android binding direction looks good, but I wasn't finding the current release flow not reproducible. From a clean checkout, publishToMavenLocal -P localBuild succeeds while publishing an empty AAR, which means publish is packaging whatever happens to be under lib/src/main/kotlin and lib/src/main/jniLibs instead of building the artifact. Also im seeing the advertised full release recipe (just clean && just build macos-aarch64) currently fails at the UniFFI generate step with No UniFFI metadata found for the release-smaller Android .so, so the documented release path must be broken?
Not sure if you've run into these or its just me and I might have done something wrong.
Im assuming you're using these on the SATSBUDDY-android app so that will be nice in checking off "does this work with a real app" part 👍

Hi man, I just pushed some fix. Could you try again?

cktap-android $ just clean && just build && just publish-local

@reez

Retested. The first two issues look fixed. I still can't tell why/where the library needs android.permission.INTERNET, since I don’t see Android side networking code in the checked sources. I might be missing it or the code path that uses it?

@r1b2ns r1b2ns changed the title [draft]feat(android): add cktap-android Kotlin/Android bindings via UniFFI feat(android): add cktap-android Kotlin/Android bindings via UniFFI Apr 15, 2026
@r1b2ns r1b2ns marked this pull request as ready for review April 15, 2026 20:34
The library has no networking code path: no HTTP/TCP clients in deps, and
the only `connect` calls in the Rust sources are `UnixStream` (emulator
feature, not built for Android) and PC/SC (smartcard, not built for
Android). The permission was inherited from the bdk-android template,
where it is needed for Electrum/Esplora — here it just pollutes the
merged manifest of every consuming app.
@r1b2ns
Copy link
Copy Markdown
Contributor Author

r1b2ns commented Apr 15, 2026

Excited this is in progress!
The Android binding direction looks good, but I wasn't finding the current release flow not reproducible. From a clean checkout, publishToMavenLocal -P localBuild succeeds while publishing an empty AAR, which means publish is packaging whatever happens to be under lib/src/main/kotlin and lib/src/main/jniLibs instead of building the artifact. Also im seeing the advertised full release recipe (just clean && just build macos-aarch64) currently fails at the UniFFI generate step with No UniFFI metadata found for the release-smaller Android .so, so the documented release path must be broken?
Not sure if you've run into these or its just me and I might have done something wrong.
Im assuming you're using these on the SATSBUDDY-android app so that will be nice in checking off "does this work with a real app" part 👍

Hi man, I just pushed some fix. Could you try again?
cktap-android $ just clean && just build && just publish-local
@reez

Retested. The first two issues look fixed. I still can't tell why/where the library needs android.permission.INTERNET, since I don’t see Android side networking code in the checked sources. I might be missing it or the code path that uses it?

You all right, fixed and tested

Copy link
Copy Markdown
Collaborator

@reez reez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 4054b9e

Woot!

@reez reez merged commit b1b6339 into bitcoindevkit:master Apr 15, 2026
10 checks passed
@r1b2ns r1b2ns deleted the feat/android-ffi branch April 15, 2026 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants