Published on

Dart 调用 Rust 代码:跨平台实践 (iOS & Android)

Authors

如何使用 Dart 来调用 Rust 的代码?

在 Dart 中调用 Rust 代码通常可以通过以下几种方式来实现:

1. 使用 FFI(Foreign Function Interface)

Dart 提供了 dart:ffi 库来调用本地共享库(如 .dll, .so, .dylib),Rust 可以编译为共享库以供 Dart 调用。

基本步骤


Step 1: 编写 Rust 代码

Rust 代码示例 (src/lib.rs):

#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

编译为共享库

# Linux/macOS
cargo build --release
# Windows
cargo build --release --target x86_64-pc-windows-gnu

target/release 中会生成以下文件:

  • Linux: libmy_rust_lib.so
  • macOS: libmy_rust_lib.dylib
  • Windows: my_rust_lib.dll

Step 2: Dart 调用 Rust

在 Dart 项目中:

import 'dart:ffi' as ffi;
import 'dart:io';

typedef AddFunc = ffi.Int32 Function(ffi.Int32, ffi.Int32);
typedef Add = int Function(int, int);

void main() {
  final lib = ffi.DynamicLibrary.open(
      Platform.isWindows ? 'my_rust_lib.dll' :
      Platform.isMacOS ? 'libmy_rust_lib.dylib' :
      'libmy_rust_lib.so');

  final addPointer = lib.lookup<ffi.NativeFunction<AddFunc>>('add');
  final add = addPointer.asFunction<Add>();

  final result = add(3, 5);
  print('3 + 5 = $result');
}

2. 使用 Flutter + Rust

如果你正在做 Flutter 开发,推荐使用 flutter_rust_bridge 这个库,它可以帮助你更高效、简洁地将 Rust 与 Flutter 集成。

简要流程

  1. 安装 flutter_rust_bridge
  2. 编写 Rust 代码并生成 API
  3. Flutter 中调用 Rust 逻辑

工具推荐

Rust 是否可以编译成兼容 iOS 和 Android 平台的代码?

是的,Rust 可以编译成兼容 iOS 和 Android 平台的代码,并且可以通过 FFI 与 Dart(Flutter)无缝集成。Rust 拥有强大的跨平台能力,并且可以通过交叉编译为 Android 和 iOS 提供共享库,从而供 Flutter 或其他移动应用调用。


🛠️ 1. 编译 Rust 代码以兼容 iOS 和 Android

1.1 编译 Rust 代码以支持 Android


💾 设置环境

  1. 安装 Android NDK(Native Development Kit):

    • 下载 Android NDK:通过 NDK 下载页面 或 Android Studio 的 SDK Manager。
    • 设置环境变量:
      export ANDROID_NDK_HOME=$HOME/Android/Sdk/ndk/25.2.9519653
      
  2. 安装 Rust 的 Android 目标架构:

    rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
    

📜 编写 Rust 代码

创建 src/lib.rs

#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

Cargo.toml

[lib]
name = "my_rust_lib"
crate-type = ["cdylib"]

[dependencies]

⚙️ 编译为 Android 的共享库

运行以下命令:

# 编译 ARM64(Android)
cargo build --release --target aarch64-linux-android

生成的库文件位于:

  • target/aarch64-linux-android/release/libmy_rust_lib.so

💡说明: Android 平台使用 .so 文件,且必须将库文件放入 android/app/src/main/jniLibs 目录中,按 CPU 架构区分子目录:

jniLibs
 ├── arm64-v8a    # 对应 aarch64-linux-android
 │   └── libmy_rust_lib.so
 ├── armeabi-v7a  # 对应 armv7-linux-androideabi
 │   └── libmy_rust_lib.so
 ├── x86_64       # 对应 x86_64-linux-android
 │   └── libmy_rust_lib.so

1.2 编译 Rust 代码以支持 iOS


💾 设置环境

  1. 安装 iOS 编译目标:

    rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
    
  2. 确保安装了 Xcode,并通过以下命令确认:

    xcode-select --install
    

📜 编写 Rust 代码

使用与 Android 相同的 src/lib.rs 文件:

#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

Cargo.toml

[lib]
name = "my_rust_lib"
crate-type = ["cdylib"]

[dependencies]

⚙️ 编译为 iOS 的共享库

# 编译 iOS(真机)
cargo build --release --target aarch64-apple-ios

# 编译 iOS 模拟器(M1/M2 芯片)
cargo build --release --target aarch64-apple-ios-sim

# 编译 iOS 模拟器(Intel 芯片)
cargo build --release --target x86_64-apple-ios

生成的库文件:

  • iOS 设备:target/aarch64-apple-ios/release/libmy_rust_lib.a
  • iOS 模拟器:target/aarch64-apple-ios-sim/release/libmy_rust_lib.a

💡 说明: iOS 平台使用 .a 静态库而不是 .so


1.3 iOS/Android 编译的关键差异

特性AndroidiOS
库文件后缀.so.a(静态库)
架构arm64-v8a, x86_64aarch64, x86_64
调用方式DynamicLibrary.openDynamicLibrary.process
NDK 依赖需要不需要

🚀 2. Dart/Flutter 中调用 Rust


2.1 调用 Android 的 Rust 代码

Dart 调用 Android Rust 共享库的示例:

import 'dart:ffi';
import 'dart:io';

typedef AddFunc = Int32 Function(Int32, Int32);
typedef Add = int Function(int, int);

void main() {
  final lib = DynamicLibrary.open('libmy_rust_lib.so');

  final addPointer = lib.lookup<NativeFunction<AddFunc>>('add');
  final add = addPointer.asFunction<Add>();

  final result = add(5, 7);
  print('5 + 7 = $result');
}

运行时注意: Android 上 .so 文件需放在 android/app/src/main/jniLibs 目录下。Flutter 会自动打包该目录内的 .so 文件到最终的 APK。


2.2 调用 iOS 的 Rust 代码

Dart 调用 iOS Rust 静态库的示例:

import 'dart:ffi';

typedef AddFunc = Int32 Function(Int32, Int32);
typedef Add = int Function(int, int);

void main() {
  final lib = DynamicLibrary.process();

  final addPointer = lib.lookup<NativeFunction<AddFunc>>('add');
  final add = addPointer.asFunction<Add>();

  final result = add(5, 7);
  print('5 + 7 = $result');
}

运行时注意

  • 需要将 libmy_rust_lib.a 添加到 Xcode 项目中的 Link Binary With Libraries
  • Dart 调用 iOS 的 Rust 函数时应使用 DynamicLibrary.process(),因为 iOS 不允许动态加载自定义共享库。

🧩 3. 高效集成:flutter_rust_bridge

如果你是 Flutter 开发者,建议使用 flutter_rust_bridge 库。它封装了 Dart 与 Rust 之间的通信,避免了手动管理 FFI 和平台兼容性的问题。

快速步骤

  1. 添加依赖:

    dependencies:
      flutter_rust_bridge: ^1.0.0
    
  2. 使用 flutter_rust_bridge_codegen 工具自动生成跨语言接口代码。

  3. 跨平台调用 Rust 逻辑时,代码完全无感知。


🧐 4. 常见问题与优化

  1. 跨平台架构支持不足

    • Android 支持 arm64-v8a, armeabi-v7a, x86, x86_64
    • iOS 支持 aarch64x86_64(模拟器)。
  2. 性能考虑

    • Rust 和 Dart 之间通过 FFI 调用有一定开销,建议避免频繁调用小函数。
    • 尝试将高频逻辑尽可能在 Rust 端完成,Dart 只调用最终结果。
  3. 安全性

    • Rust 是内存安全语言,但通过 FFI 调用仍需谨慎,避免不安全的指针传递。
  4. 动态库加载失败

    • Android:确保 jniLibs 目录中有正确的 .so 文件。
    • iOS:检查是否已正确链接 libmy_rust_lib.a

🎯 5. 结论

Rust 具备良好的跨平台能力,可以高效地为 iOS 和 Android 编译共享库,并能通过 Dart 的 dart:ffi 调用这些库,实现性能和安全性的双赢。

🔹 Android:生成 .so 文件,放置于 jniLibs。 🔹 iOS:生成 .a 文件,添加至 Xcode。 🔹 推荐工具flutter_rust_bridge 简化开发流程。

Rust 的强大性能与 Flutter 的跨平台优势相结合,为开发高性能、跨平台的移动应用提供了强有力的支持。 😊