You can integrate Rust into a Flutter app by compiling Rust code into a dynamic library (.so, .dylib, or .dll) and calling it from Flutter's platform channels using the C FFI. This approach lets you leverage Rust's performance for heavy computation while keeping the UI logic in Dart.
First, create a Rust library crate and define your functions with #[no_mangle] and extern "C" to ensure they have stable, C-compatible names. You must handle string conversions manually, typically by passing *const c_char pointers and lengths, or by using std::ffi::CStr to convert Rust strings to C strings.
// lib.rs in your Rust crate
use std::ffi::CStr;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C" fn rust_compute(input: *const c_char, len: usize) -> *mut c_char {
let c_str = unsafe { CStr::from_ptr_with_nul(input) };
let rust_str = c_str.to_str().unwrap_or("");
let result = format!("Processed: {}", rust_str);
let c_result = result.into_bytes();
// Allocate memory that Dart can free later (or manage via a custom free function)
let ptr = std::alloc::alloc(std::alloc::Layout::from_size_align(c_result.len(), 1).unwrap()) as *mut c_char;
unsafe { std::ptr::copy_nonoverlapping(c_result.as_ptr(), ptr, c_result.len()) };
ptr
}
#[no_mangle]
pub extern "C" fn rust_free(ptr: *mut c_char) {
if !ptr.is_null() {
unsafe { std::alloc::dealloc(ptr as *mut u8, std::alloc::Layout::from_size_align(1024, 1).unwrap()) };
}
}
Build this library for your target platform (e.g., cargo build --release --target aarch64-linux-android for Android) and place the resulting binary in your Flutter project's native source directory. In your Dart code, use MethodChannel to invoke the native method, which then calls the Rust function via a C wrapper or directly if using dart:ffi on desktop/web.
// main.dart
import 'package:flutter/services.dart';
class RustService {
static const platform = MethodChannel('com.example.app/rust');
static Future<String> compute(String input) async {
try {
final result = await platform.invokeMethod('compute', input);
return result;
} on PlatformException catch (e) {
return 'Error: ${e.message}';
}
}
}
// In your Android native code (jni), you would bridge the MethodChannel call to the Rust function
For a smoother experience, consider using flutter_rust_bridge, a tool that automates the FFI boilerplate, handles memory safety, and generates the necessary Dart and Rust glue code. It significantly reduces the risk of memory leaks and string encoding errors compared to manual FFI.
# Install the CLI tool
cargo install flutter_rust_bridge_codegen
# Generate bindings
flutter_rust_bridge_codegen generate
This setup allows you to offload CPU-intensive tasks like cryptography, image processing, or complex algorithms to Rust while maintaining a responsive Flutter UI. Always ensure you handle memory ownership correctly to prevent leaks, especially when passing strings or large data structures across the boundary.