Exploring whether Rust source files can be automatically parsed to generate JNI bindings, Kotlin APIs, and Android build integration through a Gradle plugin

Exploring a Gradle Plugin for Automatic Rust ↔ Kotlin Bindings on Android

Hi everyone,

I’m an Android developer currently learning Rust and experimenting with Rust integration in Android applications.

While working with Rust and Android, I noticed that even simple Rust functions require a significant amount of repetitive integration work:

  • Writing JNI bridge functions

  • Creating Kotlin external fun declarations

  • Loading native libraries

  • Building Rust for Android targets

  • Managing and copying generated .so files

  • Keeping Rust and Kotlin bindings synchronized

For example, a developer might write:

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

but still needs to manually create JNI wrappers and Kotlin bridge code before these functions can be used from Android.

Motivation

My long-term goal is to make Rust feel like a first-class citizen in Android projects, similar to how Kotlin developers can consume generated APIs without worrying about the underlying implementation details.

Rather than requiring developers to learn JNI, manage native builds, and maintain bindings manually, I would like to explore whether these steps can be automated through tooling.

Proposed Goal

I am considering a Gradle-based solution (and potentially an Android Studio plugin in the future) that would allow developers to place Rust source files directly inside an Android project.

Example project structure:

app/
rust/
 ├── math.rs
 └── greetings.rs

Developer-written Rust:

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

Automatically generated Kotlin API:

Rust.add(1, 2)
Rust.greet("World")

without manually writing:

  • JNI functions

  • Kotlin bridge classes

  • Cargo build commands

  • Native library copy logic

Proposed Architecture

My current idea is:

  1. Scan Rust source files inside a dedicated rust/ directory.

  2. Parse Rust ASTs using the syn crate.

  3. Discover public Rust functions.

  4. Generate JNI bridge code automatically.

  5. Generate Kotlin wrappers automatically.

  6. Build Rust libraries for Android targets.

  7. Copy generated native libraries into the Android build.

  8. Integrate everything into the Gradle build lifecycle.

Current Status

So far, I have successfully integrated Rust into Android manually using JNI and generated Android-compatible .so libraries.

I have not yet built the generator or plugin itself.

Before investing significant time into a proof of concept, I would like feedback on whether this architecture is reasonable and whether there are existing tools, APIs, or approaches I should investigate first.

Questions

  1. Does this architecture seem reasonable from a Gradle/Android tooling perspective?

  2. Would a Gradle plugin be a better starting point than an Android Studio plugin?

  3. Are there existing AGP or Kotlin APIs that would simplify source generation and build integration?

  4. Are there existing projects that already solve this problem in a similar way?

  5. How does this compare with UniFFI or other Rust binding-generation approaches?

  6. Are there any major technical challenges, limitations, or pitfalls that I may be overlooking?

I would greatly appreciate feedback, architectural suggestions, references to existing tooling, or advice from anyone who has worked on Gradle plugins, Android build tooling, code generation, or Rust integration projects.

Thank you!

2 Likes

I’m not really familiar with a lot of this stuff… I only have a passing familiarity with Rust, and have no idea what JNI is. But I can kind of guess.

I would say you should definitely make this a Gradle plugin, and not an Android Studio plugin. This makes it usable in any Gradle project, rather than requiring the use of Android Studio.

The other thing I would say is don’t make the Rust source directory static. Make it configurable with a sensible default. This definitely makes sense if you do it as a Gradle plugin, as Gradle already has the concept of source sets, and things like the Java plugin, Groovy plugin, Kotlin plugin etc. have default locations for the source sets, but you can customise those source sets and use different directories. (And even implement custom filtering logic to only include certain files, if you really need to)

Otherwise, this sounds like a super useful tool!

1 Like