使用 dart:ffi 的 C 語言互通性
在 Dart Native 平台上執行的 Dart 行動、命令列和伺服器應用程式可以使用 dart:ffi
函式庫來呼叫原生 C API,以及讀取、寫入、分配和釋放原生記憶體。FFI 代表外部函式介面 (foreign function interface)。類似功能的其他術語包括原生介面和語言綁定。
API 文件可在dart:ffi
API 參考中找到。
下載範例檔案
#若要使用本指南中的範例,請下載完整的ffi 範例目錄。其中包含以下範例,示範如何使用 dart:ffi
函式庫
範例 | 說明 |
---|---|
hello_world | 如何呼叫沒有引數和沒有傳回值的 C 語言函式。 |
primitives | 如何呼叫具有引數和傳回值為整數或指標的 C 語言函式。 |
structs | 如何使用 structs 來傳遞字串到 C 語言和從 C 語言傳遞字串,以及處理簡單和複雜的 C 語言結構。 |
test_utils | 適用於所有這些範例的通用測試工具。 |
檢閱 hello_world 範例
#hello_world 範例具有呼叫 C 語言函式庫所需的最低限度程式碼。此範例可在您在前一節下載的 samples/ffi
中找到。
檔案
#hello_world
範例包含下列檔案
原始碼檔案 | 說明 |
---|---|
hello.dart | 使用 C 語言函式庫中的 hello_world() 函式的 Dart 檔案。 |
pubspec.yaml | Dart pubspec 檔案,SDK 下限為 3.4。 |
hello_library/hello.h | 宣告 hello_world() 函式。 |
hello_library/hello.c | 匯入 hello.h 並定義 hello_world() 函式的 C 語言檔案。 |
hello_library/hello.def | 模組定義檔,指定建置 DLL 時使用的資訊。 |
hello_library/CMakeLists.txt | 用於將 C 語言程式碼編譯成動態函式庫的 CMake 建置檔案。 |
建置 C 語言函式庫會建立多個檔案,包括名為 libhello.dylib
(macOS)、libhello.dll
(Windows) 或 libhello.so
(Linux) 的動態函式庫檔案。
建置和執行
#用於建置動態函式庫和執行 Dart 應用程式的命令會類似於以下順序。
$ cd hello_library
$ cmake .
...
$ make
...
$ cd ..
$ dart pub get
$ dart run hello.dart
Hello World
運用 dart:ffi
#若要瞭解如何使用 dart:ffi
函式庫呼叫 C 語言函式,請檢閱 hello.dart
檔案。本節說明此檔案的內容。
匯入
dart:ffi
。dartimport 'dart:ffi' as ffi;
匯入 path 函式庫,您將使用它來儲存動態函式庫的路徑。
dartimport 'dart:io' show Platform, Directory; import 'package:path/path.dart' as path;
使用 C 語言函式的 FFI 類型簽章建立 typedef。
若要瞭解根據dart:ffi
函式庫最常用的類型,請參閱與原生類型介接。darttypedef hello_world_func = ffi.Void Function();
為呼叫 C 語言函式時要使用的變數建立 typedef。
darttypedef HelloWorld = void Function();
建立變數來儲存動態函式庫的路徑。
dartvar libraryPath = path.join(Directory.current.path, 'hello_library', 'libhello.so'); if (Platform.isMacOS) { libraryPath = path.join(Directory.current.path, 'hello_library', 'libhello.dylib'); } else if (Platform.isWindows) { libraryPath = path.join(Directory.current.path, 'hello_library', 'Debug', 'hello.dll'); }
開啟包含 C 語言函式的動態函式庫。
dartfinal dylib = ffi.DynamicLibrary.open(libraryPath);
取得 C 語言函式的參考,並將其放入變數中。此程式碼使用步驟 2 和 3 的 typedef,以及步驟 4 的動態函式庫變數。
dartfinal HelloWorld hello = dylib .lookup<ffi.NativeFunction<hello_world_func>>('hello_world') .asFunction();
呼叫 C 語言函式。
darthello();
一旦您瞭解 hello_world
範例,請參閱其他 dart:ffi
範例。
捆綁和載入 C 語言函式庫
#捆綁/封裝/發布然後載入原生 C 語言函式庫的方法取決於平台和函式庫類型。
若要瞭解如何操作,請參閱以下頁面和範例。
- 適用於 Android 應用程式的 Flutter
dart:ffi
- 適用於 iOS 應用程式的 Flutter
dart:ffi
- 適用於 macOS 應用程式的 Flutter
dart:ffi
dart:ffi
範例
與原生類型介接
#dart:ffi
函式庫提供多種實作 NativeType
並表示 C 語言原生類型的類型。您可以實例化某些原生類型。其他一些原生類型只能在類型簽章中用作標記。
可以實例化這些類型簽章標記
#以下原生類型可以用作類型簽章中的標記。它們或其子類型可以在 Dart 程式碼中實例化。
僅作為類型簽章標記
#以下列表顯示哪些平台無關的原生類型在類型簽章中用作標記。它們無法在 Dart 程式碼中實例化。
Dart 類型 | 說明 |
---|---|
Bool | 表示 C 語言中的原生布林值。 |
Double | 表示 C 語言中的原生 64 位元雙精度浮點數。 |
Float | 表示 C 語言中的原生 32 位元單精度浮點數。 |
Int8 | 表示 C 語言中的原生有號 8 位元整數。 |
Int16 | 表示 C 語言中的原生有號 16 位元整數。 |
Int32 | 表示 C 語言中的原生有號 32 位元整數。 |
Int64 | 表示 C 語言中的原生有號 64 位元整數。 |
NativeFunction | 表示 C 語言中的函式類型。 |
Opaque | C 語言中所有不透明類型的超類型。 |
Uint8 | 表示 C 語言中的原生無號 8 位元整數。 |
Uint16 | 表示 C 語言中的原生無號 16 位元整數。 |
Uint32 | 表示 C 語言中的原生無號 32 位元整數。 |
Uint64 | 表示 C 語言中的原生無號 64 位元整數。 |
Void | 表示 C 語言中的 void 類型。 |
還有許多 ABI 特定的標記原生類型擴充了 AbiSpecificInteger。若要瞭解這些類型如何在特定平台上對應,請參閱下表中連結的 API 文件。
Dart 類型 | 說明 |
---|---|
AbiSpecificInteger | 所有 ABI 特定整數類型的超類型。 |
Int | 表示 C 語言中的 int 類型。 |
IntPtr | 表示 C 語言中的 intptr_t 類型。 |
Long | 表示 C 語言中的 long int (long) 類型。 |
LongLong | 表示 C 語言中的 long long 類型。 |
Short | 表示 C 語言中的 short 類型。 |
SignedChar | 表示 C 語言中的 signed char 類型。 |
Size | 表示 C 語言中的 size_t 類型。 |
UintPtr | 表示 C 語言中的 uintptr_t 類型。 |
UnsignedChar | 表示 C 語言中的 unsigned char 類型。 |
UnsignedInt | 表示 C 語言中的 unsigned int 類型。 |
UnsignedLong | 表示 C 語言中的 unsigned long int 類型。 |
UnsignedLongLong | 表示 C 語言中的 unsigned long long 類型。 |
UnsignedShort | 表示 C 語言中的 unsigned short 類型。 |
WChar | 表示 C 語言中的 wchar_t 類型。 |
使用 package:ffigen
產生 FFI 綁定
#對於大型 API 介面,撰寫與 C 語言程式碼整合的 Dart 綁定可能很耗時。若要讓 Dart 從 C 語言標頭檔建立 FFI 包裝函式,請使用 package:ffigen
綁定產生器。
建置和捆綁原生資源
#原生資源功能應解決與依賴原生程式碼的 Dart 套件發布相關的許多問題。它透過提供統一的 hook 來與建置 Flutter 和獨立 Dart 應用程式所涉及的各種建置系統整合來實現這一點。
此功能應簡化 Dart 套件依賴和使用原生程式碼的方式。原生資源應提供以下優點
- 使用套件的
hook/build.dart
建置 hook 來建置原生程式碼或取得二進位檔。 - 捆綁
build.dart
建置 hook 報告的原生Asset
。 - 使用
assetId
透過宣告式@Native<>() extern
函式使原生資源在執行階段可用。
當您選擇加入原生實驗性功能時,flutter (run|build)
和 dart (run|build)
命令會建置原生程式碼並將其與 Dart 程式碼捆綁在一起。
檢閱 native_add_library
範例
#native_add_library
範例包含在 Dart 套件中建置和捆綁 C 語言程式碼所需的最低限度程式碼。
此範例包含下列檔案
原始碼檔案 | 說明 |
---|---|
src/native_add_library.c | 包含 add 程式碼的 C 語言檔案。 |
lib/native_add_library.dart | 透過 FFI 在資源 package:native_add_library/native_add_library.dart 中調用 C 語言函式 add 的 Dart 檔案。(請注意,資源 ID 預設為函式庫 URI。) |
test/native_add_library_test.dart | 使用原生程式碼的 Dart 測試。 |
hook/build.dart | 用於編譯 src/native_add_library.c 並宣告資源 ID 為 package:native_add_library/native_add_library.dart 的編譯資源的建置 hook。 |
當 Dart 或 Flutter 專案依賴 package:native_add_library
時,它會在 run
、build
和 test
命令上調用 hook/build.dart
建置 hook。native_add_app
範例展示了 native_add_library
的用法。
檢閱原生資源 API 文件
#以下套件的 API 文件可在以下位置找到
- 若要瞭解 Dart FFI 中的原生資源,請參閱
Native
和DefaultAsset
的dart:ffi
API 參考。 - 若要瞭解
hook/build.dart
建置 hook,請參閱package:native_assets_cli
API 參考。
選擇加入實驗性功能
#若要瞭解如何啟用實驗性功能並提供意見回饋,請參閱這些追蹤問題
除非另有說明,否則本網站上的文件反映 Dart 3.7.1 版本。頁面最後更新於 2024-11-17。 檢視原始碼 或 回報問題。