使用 dart:ffi 與原生 macOS 程式碼繫結
要在 Flutter 程式中使用 C 程式碼,請使用 dart:ffi 庫。
Flutter 移動和桌面應用可以使用 dart:ffi 庫呼叫原生 C API。FFI 是 外部函式介面 的縮寫。其他類似的術語包括原生介面和語言繫結。
在您的庫或程式可以使用 FFI 庫繫結到原生程式碼之前,您必須確保已載入原生程式碼及其符號對 Dart 可見。此頁面重點介紹在 Flutter 外掛或應用程式中編譯、打包和載入 macOS 原生程式碼。
本教程演示瞭如何在 Flutter 外掛中捆綁 C/C++ 原始碼,並使用 Dart FFI 庫在 macOS 上與其繫結。在本演練中,您將建立一個實現 32 位加法的 C 函式,然後透過名為“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 Desktop 應用程式,請使用以下說明
- 按照 Flutter desktop 的說明建立 Flutter desktop 應用程式。
- 在 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 互操作性的資訊,請檢視以下影片