How to make Flutter and Rust become a COUPLE, exactly?
Tags: Ffi, Flutter, Rust

This article is only focus on Android. After I struggle through ios, I will give you a “hint expansion”.

First Part, build the shared library.

1–1. Create a rust library on Win10.

cargo new — lib zhen

1–2. Add [lib] in Cargo.toml.

[lib]

name = “zhen”

crate-type = [“staticlib”, “cdylib”]

1–3. Create a file named zhen.rs, or anything you like, your src directory should be like:

src

└── lib.rs

└── zhen.rs

1–4. Copy code below into zhen.rs.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};



const BUFFER_MAX_SIZE: usize = 512;



#[derive(Default)]

pub struct Zhen {

init: bool,

input_buffer: Vec<u8>,

out_buffer: Vec<u8>,

}



impl Zhen {

fn init(&mut self) {

if !self.init {

self.out_buffer = Vec::with_capacity(BUFFER_MAX_SIZE);

self.input_buffer = Vec::with_capacity(BUFFER_MAX_SIZE);

self.init = true;

}

}



pub unsafe fn process_proto(&mut self, request: &[u8]) -> *const u8 {

self.init();

self.execute_proto(request);

self.out_buffer.as_ptr()

}



fn execute_proto(&mut self, request: &[u8]) {

self.input_buffer.clear();

self.out_buffer.clear();

for x in request.iter() {

self.input_buffer.push(*x);

}

let mut buf: &[u8] = self.input_buffer.as_ref();

let method_id = buf.read_u32::<LittleEndian>().expect("unable to read method id");



match method_id {

1 => {

let x = buf.read_f64::<LittleEndian>().expect("unable to read byte");

let decimal = buf.read_u32::<LittleEndian>().expect("unable to read byte");

let mode = buf.read_u32::<LittleEndian>().expect("unable to read byte");

let y = self.clip_double_decimal(x, decimal, mode);

self.out_buffer.write_f64::<LittleEndian>(y).expect("write error");

},

_ => {



}

}

}



fn clip_double_decimal(&self, x: f64, decimal: u32, mode: u32) -> f64{

let p = 10_u32.pow(decimal) as f64;

if mode == 1 {

(x * p).round() / p

} else {

(x * p).trunc() / p

}

}

1–5. Copy code below into lib.rs.

use global::Global;

mod zhen;

use std::os::raw::{c_int};

use std::slice;



static ZHEN: Global<zhen::Zhen> = Global::new();



#[no_mangle]

pub unsafe extern "C" fn rust_call(porto: *const u8, length: c_int) -> *const u8 {

let proto: &[u8] = slice::from_raw_parts(porto, length as usize);

ZHEN.lock_mut().unwrap().process_proto(proto)

}

1–6. Add [dependencies] in Cargo.toml

[dependencies]

global = “*”

byteorder = “*”

1–7. Cargo build to make sure you got 0 error and 0 warning.

1–8. Move your rust project to Linux(rust ready ofcourse), you must be familiar with at least one method, do you?

1–9. Download newest Android NDK(https://dl.google.com/android/repository/android-ndk-r21b-linux-x86_64.zip) and unzip it at path “/usr/local/android/ndk/”.

1–10. vim ~/.cargo/config. Append two settings below(change absolute directory to your own path):

[target.aarch64-linux-android]

ar = “/usr/local/android/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar”

linker = “/usr/local/android/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang” [target.armv7-linux-androideabi]

ar = “/usr/local/android/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-android-ar”

linker = “/usr/local/android/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi29-clang”

1–11. cd to your rust project and prepare to build.

cargo build — target=aarch64-linux-android — release

cargo build — target=armv7-linux-androideabi — release

1–12. Make sure you got 0 error and 0 warning, wish it…

1–13. Copy two libzhen.so back to Win10(from target/aarch64-linux-android and target/armv7-linux-androideabi). Make sure the lib name starts with “lib”, it’s too important!

FAQ about First Part.

F-1. What does the example code mean?

It’s a FFI C standard function, whose parameter is a pointer(point to a fixed-size byte buffer managed by caller) and return value is also a ponter(point to a fixed-size byte buffer managed by rust zhen). The function parse the input byte buffer and does some calculation, store the result in zhen’s buffer then return it out.

F-2. Why can’t we compile the zhen.so on Win10?

Trust me, I wish I could, too.

F-3. Why I got error on step 1–12?

If you have followd my steps and downloaded the right linux verion of NDK, I don’t know neither.