Interoperability with Java

์ž๋ฐ”๋Š” Java Native Interface(JNI)๋ฅผ ํ†ตํ•ด ๊ณต์œ  ๊ฐ์ฒด๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. jni ํฌ๋ ˆ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธํ™˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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:

#![allow(unused)]
fn main() {
//! Rust <-> Java FFI demo.

use jni::objects::{JClass, JString};
use jni::sys::jstring;
use jni::JNIEnv;

/// HelloWorld::hello method implementation.
#[no_mangle]
pub extern "system" fn Java_HelloWorld_hello(
    env: JNIEnv,
    _class: JClass,
    name: JString,
) -> jstring {
    let input: String = env.get_string(name).unwrap().into();
    let greeting = format!("Hello, {input}!");
    let output = env.new_string(greeting).unwrap();
    output.into_inner()
}
}

interoperability/java/Android.bp:

rust_ffi_shared {
    name: "libhello_jni",
    crate_name: "hello_jni",
    srcs: ["src/lib.rs"],
    rustlibs: ["libjni"],
}

๋งˆ์นจ๋‚ด, ์ž๋ฐ”์—์„œ ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Finally, we can call this function from Java:

interoperability/java/HelloWorld.java:

class HelloWorld {
    private static native String hello(String name);

    static {
        System.loadLibrary("hello_jni");
    }

    public static void main(String[] args) {
        String output = HelloWorld.hello("Alice");
        System.out.println(output);
    }
}

interoperability/java/Android.bp:

java_binary {
    name: "helloworld_jni",
    srcs: ["HelloWorld.java"],
    main_class: "HelloWorld",
    required: ["libhello_jni"],
}

๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋นŒ๋“œ, ์‹ฑํฌ, ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

Finally, you can build, sync, and run the binary:

$ m helloworld_jni
$ adb sync  # requires adb root && adb remount
$ adb shell /system/bin/helloworld_jni