使用 dart:ffi 繫結到原生 macOS 程式碼
Flutter 移動和桌面應用可以使用 dart:ffi 庫呼叫原生 C API。FFI 是 外部函式介面 的縮寫。其他類似的術語包括原生介面和語言繫結。
在您的庫或程式可以使用 FFI 庫繫結到原生程式碼之前,您必須確保原生程式碼已載入並且其符號對 Dart 可見。本頁重點介紹在 Flutter 外掛或應用中編譯、打包和載入 macOS 原生程式碼。
本教程演示瞭如何在 Flutter 外掛中捆綁 C/C++ 原始檔,並使用 Dart FFI 庫在 macOS 上繫結到它們。在本演練中,您將建立一個 C 函式來實現 32 位加法,然後透過一個名為“native_add”的 Dart 外掛將其公開。
動態連結與靜態連結
#原生庫可以動態或靜態地連結到應用中。靜態連結庫嵌入到應用的 executables 映像中,並在應用啟動時載入。
可以透過 DynamicLibrary.executable 或 DynamicLibrary.process 載入靜態連結庫的符號。
相比之下,動態連結庫分發在應用的單獨檔案或資料夾中,並按需載入。在 macOS 上,動態連結庫以 .framework 資料夾的形式分發。
可以使用 DynamicLibrary.open 將動態連結庫載入到 Dart 中。
API 文件可從 Dart API 參考文件 獲取。
建立 FFI 外掛
#如果您已有外掛,請跳過此步驟。
要建立名為“native_add”的外掛,請執行以下操作:
flutter create --platforms=macos --template=plugin_ffi native_add
cd native_add這將在 native_add/src 中建立一個包含 C/C++ 原始碼的外掛。這些原始碼由不同作業系統構建資料夾中的原生構建檔案構建。
FFI 庫只能繫結 C 符號,因此在 C++ 中,這些符號會被標記為 extern "C"。
您還應該新增屬性來指示這些符號是從 Dart 引用的,以防止連結器在連結時最佳化期間丟棄這些符號。__attribute__((visibility("default"))) __attribute__((used))。
在 iOS 上,native_add/macos/native_add.podspec 會連結程式碼。
原生程式碼在 lib/native_add_bindings_generated.dart 中從 Dart 呼叫。
繫結是使用 package:ffigen 生成的。
其他用例
#iOS 和 macOS
#動態連結庫在應用啟動時由動態連結器自動載入。可以使用 DynamicLibrary.process 解析它們的符號。您還可以使用 DynamicLibrary.open 獲取庫的控制代碼以限制符號解析範圍,但尚不清楚 Apple 的稽核流程如何處理。
靜態連結到應用程式二進位制檔案中的符號可以使用 DynamicLibrary.executable 或 DynamicLibrary.process 進行解析。
平臺庫
#要連結到平臺庫,請使用以下說明
- 在 Xcode 中,開啟
Runner.xcworkspace。 - 選擇目標平臺。
- 在 **Linked Frameworks and Libraries** 部分單擊 **+**。
- 選擇要連結的系統庫。
第一方庫
#第一方原生庫可以包含為原始檔,也可以包含為(已簽名的).framework 檔案。可能也可以包含靜態連結的存檔,但這需要進行測試。
原始檔
#要直接連結到原始檔,請按照以下說明操作:
在 Xcode 中,開啟
Runner.xcworkspace。將 C/C++/Objective-C/Swift 原始檔新增到 Xcode 專案。
在匯出的符號宣告中新增以下字首,以確保它們對 Dart 可見:
C/C++/Objective-C
objcextern "C" /* <= C++ only */ __attribute__((visibility("default"))) __attribute__((used))Swift
swift@_cdecl("myFunctionName")
已編譯(動態)庫
#要連結到已編譯的動態庫,請按照以下說明操作:
- 如果存在已正確簽名的
Framework檔案,請開啟Runner.xcworkspace。 - 將框架檔案新增到 **Embedded Binaries** 部分。
- 也將其新增到 Xcode 中目標的 **Linked Frameworks & Libraries** 部分。
已編譯(動態)庫(macOS)
#要為 Flutter macOS 桌面 應用新增閉源庫,請按照以下說明操作:
- 按照 Flutter 桌面應用的說明建立 Flutter 桌面應用。
- 在 Xcode 中開啟
yourapp/macos/Runner.xcworkspace。- 將您的預編譯庫(
libyourlibrary.dylib)拖到Runner/Frameworks資料夾中。 - 單擊
Runner並轉到 **Build Phases** 選項卡。- 將
libyourlibrary.dylib拖到 **Copy Bundle Resources** 列表中。 - 在
Embed Libraries下,勾選Code Sign on Copy。 - 在
Link Binary With Libraries下,將狀態設定為Optional。(我們使用動態連結,無需靜態連結。)
- 將
- 單擊
Runner並轉到 **General** 選項卡。- 將
libyourlibrary.dylib拖到 **Frameworks, Libraries and Embedded Content** 列表中。 - 選擇 **Embed & Sign**。
- 將
- 單擊 **Runner** 並轉到 **Build Settings** 選項卡。
- 在 **Search Paths** 部分配置 **Library Search Paths**,以包含
libyourlibrary.dylib所在路徑。
- 在 **Search Paths** 部分配置 **Library Search Paths**,以包含
- 將您的預編譯庫(
- 編輯
lib/main.dart。- 使用
DynamicLibrary.open('libyourlibrary.dylib')來動態連結符號。 - 在小部件中的某個位置呼叫您的原生函式。
- 使用
- 執行
flutter run並檢查您的原生函式是否被呼叫。 - 執行
flutter build macos來構建一個自包含的釋出版本應用。
其他資源
#要了解更多關於 C 互操作性的資訊,請檢視以下影片