Interoperability with Java
Java can load shared objects via Java Native Interface (JNI). The jni crate allows you to create a compatible library.
First, we create a Rust function to export to Java:
interoperability/java/src/lib.rs:
1. ```
#![allow(unused)]
```
2. ```
fn main() {
```
3. ```
//! Rust <-> Java FFI demo.
```
5. ```
use jni::objects::{JClass, JString};
```
6. ```
use jni::sys::jstring;
```
7. ```
use jni::JNIEnv;
```
9. ```
/// HelloWorld::hello method implementation.
```
10. ```
// SAFETY: There is no other global function of this name.
```
11. ```
#[unsafe(no_mangle)]
```
12. ```
pub extern "system" fn Java_HelloWorld_hello(
```
13. ```
mut env: JNIEnv,
```
14. ```
_class: JClass,
```
15. ```
name: JString,
```
16. ```
) -> jstring {
```
17. ```
let input: String = env.get_string(&name).unwrap().into();
```
18. ```
let greeting = format!("Hello, {input}!");
```
19. ```
let output = env.new_string(greeting).unwrap();
```
20. ```
output.into_raw()
```
21. ```
}
```
22. ```
}
```
interoperability/java/Android.bp:
1. rust_ffi_shared {
2. name: "libhello_jni",
3. crate_name: "hello_jni",
4. srcs: ["src/lib.rs"],
5. rustlibs: ["libjni"],
6. }
We then call this function from Java:
interoperability/java/HelloWorld.java:
1. class HelloWorld {
2. private static native String hello(String name);
4. static {
5. System.loadLibrary("hello_jni");
6. }
8. public static void main(String[] args) {
9. String output = HelloWorld.hello("Alice");
10. System.out.println(output);
11. }
12. }
interoperability/java/Android.bp:
1. java_binary {
2. name: "helloworld_jni",
3. srcs: ["HelloWorld.java"],
4. main_class: "HelloWorld",
5. required: ["libhello_jni"],
6. }
Finally, you can build, sync, and run the binary:
1. m helloworld_jni
2. adb sync # requires adb root && adb remount
3. adb shell /system/bin/helloworld_jni
