- This Repository provide tools to bind rust interface with other language and export library artifact directly.
- It generate bindings from a Rust package and packaged to android aar or iOS lib. You don't need to write jni or other ffi code with this tool.
- Setup rust environment.
- Install 'rsbind'.
cargo install --git https://github.com/sidneywang/rsbind.git --force -- rsbind
- Create a Rust library, which contains two directory, contract and imp. You can put your interface to contract module and implemation to imp module. Expose these two modules in lib.rs.
// such as your code in contract dir as below:
pub trait YourContract {
fn test_simple(arg1: i32, arg2: String) -> String;
fn test_callback(arg: Box<Callback>);
fn test_struct() -> StructSimple;
}
pub trait Callback {
fn on_callback(arg1: i64, arg2: String);
}
pub struct StructSimple {
pub arg3: String,
pub arg4: bool,
}
// Your implementation is as below
pub struct YourImplemetation {}
impl YourContract for YourImplemetation {
fn test_simple(arg1: i32, arg2: String) -> String {
format!("Your test_simple result is {}_{}", arg1, arg2)
}
fn test_callback(arg: Box<Callback>) {
arg.on_callback(123i64, "hello callback".to_owned());
}
fn test_struct() -> StructSimple {
StructSimple {
arg1: "struct".to_owned(),
arg2: true
}
}
}
- Run rsbind command as below. Then the generated code will be in _gen directory and aar/framework will be in target directory.
Rsbind usage:
rsbind path-of-project android/ios/all ast/bridge/artifact/header/build/all
- ast: generate simplified ast files with json format to _gen/ast.
- bridge: generate c methods to expose our interface to _gen/[ios/android]_bridge.
- artifact: generate java/swift wrapper and c header, and then put then into a project(_gen/[ios/android]_artifact).
- build: build bridge modules and copy output to artifact project and then build artifact project.
- all: run all the steps for binding.
- It will generate java files packaged in aar or cocoapods lib, then you can integrated them to your android/iOS project and call the functions. For android, you can call like as below:
YourContract.test_callback(new Callback(){
void on_callback(long arg1, String arg2) {
// do your things.
}
})
Swift is very similar.
You can create a file named Rsbind.toml to add some configuration.
[android]
rustc_param = ""
arch = ["armv7-linux-androideabi"]
arch_64 = ["aarch64-linux-android"]
arch_x86 = ["i686-linux-android"]
release = true
namespace = "com.afoxer.xxx.ffi"
so_name = "demo"
ext_lib = []
features_def = ["xxxx=[]"]
[ios]
rustc_param = ""
arch_phone = ["armv7-apple-ios"]
arch_simu = ["i386-apple-ios", "x86_64-apple-ios"]
release = true
features_def = []
- Parameters: Basic types, Callback, Vec
- Return: Basic types, Struct, Vec
supported types in Callback:
- Parameters: Basic types, Vec, Struct
- Return: Basic types.
TODO: add callback support for return types.
It is different to define a callback and a normal trait. It should contains &self in every callback but not in normal trait.
Callback:
pub trait Callback : Sync {
fn on_callback(&self, arg1: i32, arg2: String, arg3: bool, arg4: f32, arg5: f64) -> i32;
fn on_callback2(&self, arg1: bool) -> bool;
fn on_callback_complex(&self, arg1: StructSimple) -> bool;
fn on_callback_arg_vec(&self, arg1: Vec<StructSimple>) -> bool;
fn on_callback_arg_vec_simple(&self, arg1: Vec<String>) -> bool;
}
Normal trait:
pub trait TestContract1 {
fn test_arg_vec(arg: Vec<String>) -> i32;
fn test_return_vec(arg: u8) -> Vec<i32>;
fn test_arg_callback(arg: Box<Callback>) -> u8;
fn test_bool(arg1: bool) -> bool;
fn test_struct() -> StructSimple;
fn test_struct_vec() -> Vec<StructSimple>;
}