Post Thumbnail f334b6e2-5735-4e2c-9788-c44b0a3690dd
Run Rust in Flutter with FFI
使用 Dart FFI 在 Flutter 中執行 Rust 代碼

發布於 2023/1/10 • 最後修改於 2023/1/10

在 Dart 中,有一個稱為 dart:ffi 的模組,FFI 全稱「外部函式接口 (Foreign function interface)」,用來使 Dart 能呼叫原生 C API。

但是,相較於 C,Rust 擁有更好的記憶體安全性、完善的包管理系統以及不遜於 C 的速度和記憶體效率。

所以我們將使用 GitHub 上的開源項目 flutter_rust_bridge 來實現 Rust FFI。

本文範例為 Windows Build,其他平台請參照 官方文檔 調整。

實現

  1. 安裝 LLVM
    • 下載 LLVM 或執行 winget install -e —id LLVM.LLVM
  2. 在專案根目錄執行 cargo new —lib ./native
  3. 編輯 Cargo.toml
+[lib]
+crate-type = [“lib”, “staticlib”, “cdylib”]

+[dependencies]
+flutter_rust_bridge = “1”
+anyhow = “1”
  1. 安裝依賴

    • Flutter
    flutter pub add ffi flutter_rust_bridge freezed_annotation
    flutter pub add dev ffigen build_runner freezed
    
    • Cargo
    cargo install flutter_rust_bridge_codegen
    
    # Optional
    cargo install cargo-xcode
    
  2. 編輯 /windows 下的 CMake 設定

    • 下載 rust.cmake 並加入到 /windows/rust.cmake
    • 編輯 /windows/CMakeLists.txt
    # Generated plugin build rules, which manage building the plugins and adding
    # them to the application.
    include(flutter/generated_plugins.cmake)
    
    +include(./rust.cmake)
    
    # === Installation ===
    # Support files are copied into place next to the executable, so that it can
    
  3. 動態連結 Dart 庫

    • 下載 ffi.dart 並加入到 /lib/ffi.dart
  4. 收尾

    • 生成代碼
    flutter pub get
    
    flutter_rust_bridge_codegen \
    	rust-input native/src/api.rs \
    	dart-output lib/bridge_generated.dart \
    	dart-decl-output lib/bridge_definitions.dart
    
    flutter pub run build_runner build
    

展示

現在應該能正常呼叫及使用了!

import “ffi.dart”;


  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FutureBuilder<Platform>(
                future: ffi.platform(),
                builder: (BuildContext context, AsyncSnapshot<Platform> snapshot) {
                  if (snapshot.hasData) {
                    return Text(
                      snapshot.data.toString(),
                      style: const TextStyle(
                        fontSize: 40,
                      ),
                    );
                  } else {
                    return const Text(
                      “Fetching Data”,
                      style: TextStyle(
                        fontSize: 40,
                      ),
                    );
                  }
                },
              ),
          ],
        ),
      ),
    );
  }

延伸

一般情況下,每次 Rust 端有更改都要重新執行一次完整的 Build Command,但這是有捷徑能走的,我們可以使用文檔中提及的 just 來達成自訂指令生成。

  1. 安裝 just
# 三擇一即可

cargo install just

scoop install just

choco install just
  1. 在專案根目錄新增 /justfile
set shell := [“cmd.exe”, “/c”]

default: gen lint

gen:
    flutter pub get
    flutter_rust_bridge_codegen \
        —rust-input native/src/api.rs \
        —dart-output lib/bridge_generated.dart \
        —dart-decl-output lib/bridge_definitions.dart
    flutter pub run build_runner build

lint:
    cd native && cargo fmt
    dart format .

clean:
    flutter clean
    cd native && cargo clean
    
serve *args=”:
    flutter pub run flutter_rust_bridge:serve {{args}}
  1. 使用
    • 更改 Rust 檔案之後在命令行執行 justjust gen 即可

補充

專案結構和名稱在符合規範的情況下是可以更改的,但記得要連設定檔一起更改

結語

以上就是如何在 Flutter 中利用 FFI 執行 Rust 代碼的介紹及教學,感謝閱讀。

參考資料